$bash -c "sleep 5 | false" & wait $!
[1] 46950
[1]+ Exit 1 bash -c "sleep 5 | false"
$echo $?
1
这有效,并在5秒后返回提示.
$bash -c "sleep 5 | false" & wait $! | true
[1] 49493
-bash: wait: pid 49493 is not a child of this shell
hbaba@mbp-005063:~/misc$echo $?
0
hbaba@mbp-005063:~/misc$ps -T -f
UID PID PPID C STIME TTY TIME CMD
980771313 49493 69771 0 12:56AM ttys056 0:00.00 bash -c sleep 5 | false
980771313 49498 49493 0 12:56AM ttys056 0:00.00 sleep 5
0 49555 69771 0 12:56AM ttys056 0:00.01 ps -T -f
这里发生了什么?
我使用的是bash版GNU bash,版本3.2.57(1)-release(x86_64-apple-darwin15)
我每次都可以重现等待错误.
我认为这与每个管道是一个单独的子shell有关. https://unix.stackexchange.com/a/127346/212862
也许等待$! command在错误的shell中查找子进程.
错误消息提到49493 pid.这确实是bash -c …命令的正确pid. ps -T表明了这一点.
更新
我对&和bash之间的bash中的运算符优先级有误解.和|. @randomir在他的answer中指出了这一点.添加花括号使得等待先前的后台进程等待.例如:
{ bash -c "sleep 5 | false" & wait $! ; } | true
这不会返回相同的等待错误.
解决方法:
这里有两个要点:
> wait(内置shell)只能等待(shell的)子进程
>管道中的每个命令都在一个单独的子shell中运行
所以,当你说:
cmd & wait $!
然后cmd在你当前的shell中运行,在后台运行,而wait(作为shell的内置)可以等待cmd的PID,因为cmd是那个shell的子代(因此是等待的子代).
另一方面,当你说:
cmd & wait $! | cmd2
那么cmd仍然在你当前的shell中运行,但是管道会引入一个新的子shell用于等待(一个新的bash进程),其中cmd不是它的子进程,而wait不能等待它的兄弟(它的父进程的子进程).
作为shell语法的另一个澄清 – &运算符(以及;,&&和||)分隔管道,形成列表.因此,列表是一系列管道,而管道是由|分隔的一系列命令.
这意味着上面的最后一个例子相当于:
cmd & { wait $! | cmd2; }
而不是这个:
{ cmd & wait $! ; } | cmd2
这相当于你的预期.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。