shell脚本进入 并退出docker容器 shell 退出脚本执行_重定向

shell代码


无意间看到群里有人在问一个问题,一个shell脚本,后来的两条命令都没执行,就退出了,是什么原因?




shell脚本进入 并退出docker容器 shell 退出脚本执行_子进程_02

群内讨论



我们知道,Shell脚本不同于其他编程语言,默认情况下,只要不出现语法错误以及中途没有主动退出的命令,哪怕你的代码全是报错,也会一行不落的全部执行完毕而不会中途退出,很显然,从群友的描述中可以看到,后来的sed命令和mv命令都没有执行,脚本就退出了。

我审查一下代码,发现并没有语法错误,也没有exit等命令,就一个很简单的shell的脚本。

那这是怎么回事呢?

exec命令作怪

他说执行get_user 函数之后,就完了,定位到代码中,感觉没什么特别的,就是通过某个命令执行一条SQL查询语句,我不明白他为什么要使用exec命令去执行后面的sh_cqlsh命令,很明显,他也并没有搞清楚exec命令的使用场景,无形之中给自己挖了一个所谓的“坑”,否则,就不会出现他所说的问题了。

因为通过exec执行命令,当命令执行完终止之后,这个脚本也会强制退出。也就是说sh_cqlsh执行完了,脚本也就退出了,剩下的命令自然就不会执行了。

通常情况下,shell会派生(fork)一个子进程去执行命令,执行完后再返回到父进程,子进程的状态不会影响到父进程。但exec不一样,它是shell的内置的一个命令,它的作用是替换当前进程,而不是fork出一个子进程。

以下是一个例子:




shell脚本进入 并退出docker容器 shell 退出脚本执行_重定向_03


通过./exectst.sh执行这个脚本时,当前shell会fork一个子进程去执行exectst.sh这个脚本,在第三行执行exec后,脚本就退出了,而后面的命令就没执行了。

因为是子进程,所以并不会影响当前的shell。

shell代码如下:

#!/bin/bashexec echo "Exiting "$0" at line $LINENO."   # Exit from script here.# $LINENO is an internal Bash variable set to the line number it's on.# ----------------------------------# The following lines never execute.echo "This echo fails to echo."exit 99                       #  This script will not exit here.                              #  Check exit value after script terminates                              #+ with an 'echo $?'.                              #  It will *not* be 99.

但如果直接在当前终端下通过exec 去执行这个脚本,那么就会退出这个终端,因为直接影响当前shell进程。


shell脚本进入 并退出docker容器 shell 退出脚本执行_怎么回退执行过的脚本_04


通常情况下,exec很少用到这样的场景,这显得多此一举,但exec有一个非常重要的作用,就是重定向文件描述符,这个则比较常用而且也很用。

比如,有这样一个需求,我需要执行一个脚本,希望这个脚本的输出内容输出到屏幕的同时希望它的全部内容能够主动记录到一个日志文件,就可以利用exec对文件描述符重定向,再利用tee这个命令进行实现。测试代码如下:

#!/bin/bashfifofile=$(mktemp -u)printout=/tmp/this.log# 创建管道文件mkfifo $fifofile;# 后台执行,利用tee输出到屏幕和日志文件cat $fifofile | tee $printout &exec 1>$fifofile # 标准输出重定向到管道文件exec 2>&1        # 标准错误重定向标准输出# echo {1..10}# 随便搞一个命令,触发错误jlfjalfjaljl echo doneecho

测试结果如图,看到了屏幕的输出,同时也记录到了日志文件。


shell脚本进入 并退出docker容器 shell 退出脚本执行_子进程_05


总而言之,shell有太多太多的所谓的“坑”,但其实都是因为人们对shell了解的不够深入,也难怪,主要是shell要记的东西太多,就各种特殊字符都能让人焦头烂额,而且有非常非常多的细节需要注意,很多刚学shell的新同学,甚至连单双引号的区别都不够了解,导致遇到各种各样的问题。