为什么这种差异很重要?下面代码中的两个块的不同之处在于最后一行:
#!/bin/bash
if [[ -n "$1" ]]; then
sleep 1 &
p=$!
kill $p &> /dev/null
else
sleep 1 &
p=$!
kill $p &> /dev/null
/bin/true # This line is the sole difference.
fi
命名它a.sh
,然后我就得到了(在我的 Linux 机器上)
$ ./a.sh
/a.sh: line 16: 18103 Terminated sleep 1
$ ./a.sh foo
$ # no "Terminated" message
为什么第二种情况没有消息? Bash 的基本行为是打印“Termied”(看到这个问题)。
(注意我p=$!
在我的真实代码中使用,但在上面的情况下你可以使用kill $!
。)
编辑:谢尔盖·科洛迪亚日内请提及问题“为何真假如此之大?”在评论中。(有点题外话,但读起来很有趣。)不幸的是,该评论所属的答案被删除了,所以我在这里记录一下。谢谢Sergiy。
答案1
按照马泰奥·意大利的回答:
相反,用killall 做同样的实验,通常会立即产生“killed”消息,表明时间/上下文切换/执行外部命令所需的任何内容都会导致足够长的延迟,以便在控制权返回到 shell 之前杀死进程。
换句话说,调用外部引起的延迟/bin/true
导致了延迟,这使得shell可以打印消息。
我还使用/bin/echo
vs进行了测试echo
:
#!/bin/bash
if [[ -n "$1" ]]; then
sleep 1 &
p=$!
kill $p &> /dev/null
/bin/echo "a line"
else
sleep 1 &
p=$!
kill $p &> /dev/null
fi
使用这个脚本:
$ bash ./mystery.sh
$ bash ./mystery.sh foo
a line
./mystery.sh: line 11: 10361 Terminated sleep 1
内置echo
:
$ bash ./mystery.sh
$ bash ./mystery.sh foo
a line
换句话说,调用外部可执行文件这一事实会强制 shell 在最后一个子进程返回时执行子进程和后台作业的检查。的情况下:
if [[ -n "$1" ]]; then
sleep 1 &
p=$!
kill $p &> /dev/null
从您的原始脚本中,没有调用任何额外的命令,只有最后内置的命令。
除此之外,我还进行了一些测试strace
:
看起来父进程退出并且不等待子进程。换句话说,shell 的父进程退出得太早执行显式检查。
$ strace -s 1024 -e kill bash mystery.sh
kill(9830, SIGTERM) = 0
mystery.sh: line 11: 9830 Terminated sleep 1
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=9830, si_uid=1000, si_status=SIGTERM, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
$ strace -s 1024 -e kill bash mystery.sh foo
kill(9839, SIGTERM) = 0
+++ exited with 0 +++
值得注意的是,在使用位置参数进行跟踪时,等待调用也不存在:
$ strace -s 1024 -e kill,wait4 bash mystery.sh foo
kill(9910, SIGTERM) = 0
+++ exited with 0 +++
$ strace -s 1024 -e kill,wait4 bash mystery.sh
kill(9916, SIGTERM) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=9916, si_uid=1000, si_status=SIGTERM, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGTERM}], WNOHANG, NULL) = 9916
wait4(-1, 0x7ffe8e5bb110, WNOHANG, NULL) = -1 ECHILD (No child processes)
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 9917
mystery.sh: line 11: 9916 Terminated sleep 1
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9917, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffe8e5bb250, WNOHANG, NULL) = -1 ECHILD (No child processes)
+++ exited with 0 +++