POSIX sh: 复合命令如何与管道一起工作?
POSIX sh: how do compound commands work with pipes?
我试图了解顺序命令组(在 GNU bash 手册中称为“列表”)如何与 POSIX sh 定义或其实现中的管道一起工作。例如下面的代码:
if test-expr1; then
cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6
此处,管道有两个连续的“列表”和一个命令,其中 cmd2
在 cmd1
完成后执行,cmd5
在 cmd4
后执行。但是,所有三个都是 运行 并行的,因此管道不会阻塞。
我的第一个猜测是,对于这些“列表”中的每一个,都会创建一个子shell,它有一个单独的 PID,它按顺序执行所有命令,但不会阻止 shell 从产生其他进程 — 如果 shell 开始等待 cmd1
完成,就会发生这种情况。但是,这是不正确的,因为 echo $$
即使在管道命令列表中仍然报告相同的 PID。
问题是:究竟如何使用 fork()/waitpid() 来实现正确的行为?
if test-expr1; then
cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6
将在解析树中呈现为:
_______________|
/ \
________________|___ \
/ \ \
IF__________________ \ \
/ \ \ \ \
test-expr1 cmd1; cmd2; cmd3 (nil) cmd4; cmd5; cmd6
看着树叶:
- test-expr1: 可能会分叉,如果它涉及 运行ning 命令,否则不需要。
- 命令1; ...:可能会分叉,除非它们是内部结构。一个分叉 shell 可以 运行 这些顺序
- 命令4; cmd5:可能会分叉,除非是内部结构。一个分叉 shell 可以 运行 这些 seq.
- cmd6:可能会分叉,除非内部。一个分叉的 shell 可以执行这个。
IF statemnet (1, 2) 通过管道传输到 (3)。 (3) 通过管道传输到 4。因此,如果您的命令是:
if /bin/echo You; then /bin/echo say; /bin/echo hi; fi | { cat -; echo I; echo say; echo Lo; } | cat -;
你得到输出:
You
say
hi
I
say
Lo
This was incorrect, though, as echo $$ still reports the same PID even in piped command lists.
这是正确的,但您的检查方法不正确。来自 bash manual:
($$) Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell.
因此您检查了调用 shell 在所有子shell 中是否相同。是的。
我试图了解顺序命令组(在 GNU bash 手册中称为“列表”)如何与 POSIX sh 定义或其实现中的管道一起工作。例如下面的代码:
if test-expr1; then
cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6
此处,管道有两个连续的“列表”和一个命令,其中 cmd2
在 cmd1
完成后执行,cmd5
在 cmd4
后执行。但是,所有三个都是 运行 并行的,因此管道不会阻塞。
我的第一个猜测是,对于这些“列表”中的每一个,都会创建一个子shell,它有一个单独的 PID,它按顺序执行所有命令,但不会阻止 shell 从产生其他进程 — 如果 shell 开始等待 cmd1
完成,就会发生这种情况。但是,这是不正确的,因为 echo $$
即使在管道命令列表中仍然报告相同的 PID。
问题是:究竟如何使用 fork()/waitpid() 来实现正确的行为?
if test-expr1; then
cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6
将在解析树中呈现为:
_______________|
/ \
________________|___ \
/ \ \
IF__________________ \ \
/ \ \ \ \
test-expr1 cmd1; cmd2; cmd3 (nil) cmd4; cmd5; cmd6
看着树叶:
- test-expr1: 可能会分叉,如果它涉及 运行ning 命令,否则不需要。
- 命令1; ...:可能会分叉,除非它们是内部结构。一个分叉 shell 可以 运行 这些顺序
- 命令4; cmd5:可能会分叉,除非是内部结构。一个分叉 shell 可以 运行 这些 seq.
- cmd6:可能会分叉,除非内部。一个分叉的 shell 可以执行这个。
IF statemnet (1, 2) 通过管道传输到 (3)。 (3) 通过管道传输到 4。因此,如果您的命令是:
if /bin/echo You; then /bin/echo say; /bin/echo hi; fi | { cat -; echo I; echo say; echo Lo; } | cat -;
你得到输出:
You
say
hi
I
say
Lo
This was incorrect, though, as echo $$ still reports the same PID even in piped command lists.
这是正确的,但您的检查方法不正确。来自 bash manual:
($$) Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell.
因此您检查了调用 shell 在所有子shell 中是否相同。是的。