bash 如果之后使用管道,为什么等待会生成“<pid> 不是此 shell 的子级”错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46752794/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does wait generate “<pid> is not a child of this shell” error if a pipe is used afterwards?
提问by Hakan Baba
In the following I create a background process and wait for it to complete.
下面我创建一个后台进程并等待它完成。
$ bash -c "sleep 5 | false" & wait $!
[1] 46950
[1]+ Exit 1 bash -c "sleep 5 | false"
$ echo $?
1
This works and the prompt returns after 5 seconds.
这有效并且提示在 5 秒后返回。
However, wait
returns an error if I use one more pipe after it.
但是,wait
如果我在它之后再使用一个管道,则会返回错误。
$ 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
What is happening here?
这里发生了什么?
I am using bash version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
我正在使用 bash 版本 GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15)
I can reproduce the wait error every time. I thinkit has something to do with each pipe being a separate subshell. https://unix.stackexchange.com/a/127346/212862
我每次都可以重现等待错误。我认为这与每个管道都是一个单独的子外壳有关。https://unix.stackexchange.com/a/127346/212862
Maybe the wait $! command looks for the child process in the wrong shell.
The error message mentions the 49493 pid. That is indeed the right pid for the bash -c …
Command. The ps -T
shows that.
也许等待$!命令在错误的 shell 中查找子进程。错误消息提到了 49493 pid。这确实是bash -c …
命令的正确 pid 。这ps -T
表明。
There are relevant questions q1and q2. But in them there is no pipe usage after the wait
built-in.
有相关的问题q1和q2。但是在它们中,wait
内置之后没有管道使用。
Update
更新
I had a misunderstanding about operator precedence in bash between the &
and |
. @randomir pointed that out in his answer. Adding curly braces makes the wait
wait on the previously backgrounded process. For example:
我对 bash 中&
和之间的运算符优先级有误解|
。@randomir 在他的回答中指出了这一点。添加花括号使wait
之前的后台进程等待。例如:
{ bash -c "sleep 5 | false" & wait $! ; } | true
This does not return the same wait error.
这不会返回相同的等待错误。
回答by randomir
There are two key points to observe here:
这里有两个关键点需要注意:
wait
(a shell built-in) can wait only (the shell's) children- each command in a pipeline runs in a separate subshell
wait
(内置外壳)只能等待(外壳的)孩子- 管道中的每个命令都在单独的子 shell 中运行
So, when you say:
所以,当你说:
cmd & wait $!
then cmd
is run in your current shell, in background, and wait
(being the shell's built-in) can wait on cmd
's PID, since cmd
is a child of that shell (and therefore a child of wait
).
thencmd
在您当前的 shell 中在后台运行,并且wait
(作为 shell 的内置)可以等待cmd
的 PID,因为它cmd
是该 shell 的子级(因此是 的子级wait
)。
On the other hand, when you say:
另一方面,当你说:
cmd & wait $! | cmd2
then cmd
is still run in your current shell, butthe pipe induces a new subshell for wait
(a new bash
process) in which cmd
is not its child, and wait
can not wait on its sibling(a child of its parent).
那么cmd
仍然是在当前的shell中运行,但管道引起一个新的子shell wait
(新bash
工艺),其中cmd
是不是它的孩子,并且wait
可以在它的兄弟迫不及待(其父母的孩子)。
As an additional clarification of shell's grammar - the &
operator (along with ;
, &&
and ||
) separates pipelines, forming lists. So, a listis a sequence of pipelines, and a pipelineis a sequence of commands separated by |
.
作为 shell 语法的额外说明 -&
运算符(连同;
,&&
和||
)分隔管道,形成列表。因此,列表是一系列管道,而管道是由 分隔的命令序列|
。
That means the last example above is equivalent to:
这意味着上面的最后一个例子相当于:
cmd & { wait $! | cmd2; }
and notto this:
而不是这个:
{ cmd & wait $! ; } | cmd2
which is equivalent to what you have expected.
这相当于您的预期。
回答by Renaud Pacalet
Bash manual:
Bash手册:
Each command in a pipeline is executed as a separate process (i.e., in a subshell).
管道中的每个命令都作为单独的进程(即,在子外壳中)执行。
You can check this with:
您可以通过以下方式检查:
$ echo "me1: $BASHPID"
me1: 34438
$ sleep 100 &
[1] 34989
$ echo "me2: $BASHPID, child: $!"
me2: 34438, child: 34989
$ true | echo "me3: $BASHPID, child: $!"
me3: 34991, child: 34989
The first and second echo
(me1
and me2
) are executed in the context of the top shell (34438
). The sleep
child process (34989
) is one of its children. The third echo
(me3
) is executed in the context of a subshell (34991
). The sleep
process is not one of its children any more.
第一个和第二个echo
( me1
and me2
) 在顶层 shell ( 34438
)的上下文中执行。该sleep
子进程(34989
)是它的一个子。第三个echo
( me3
) 在子外壳 ( 34991
)的上下文中执行。该sleep
进程不再是它的子进程之一。