POSIX sh:复合命令如何与管道一起使用?

时间:2020-08-25 18:32:45

标签: bash shell sh posix

我试图了解顺序命令组(在GNU bash手册中称为“列表”)如何与POSIX sh定义或其实现中的管道一起使用。例如,以下代码:

if test-expr1; then
  cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6

此处,管道具有两个顺序的“列表”和一个命令,其中cmd2cmd1完成后执行,cmd5cmd4之后执行。但是,所有这三个都是并行运行的,因此管道不会阻塞。

我的第一个猜测是,为每个“列表”创建了一个带有单独PID的子shell,该子shell按顺序执行所有命令,但不会阻止shell产生其他进程-如果shell发生了开始等待cmd1完成。不过,这是错误的,因为echo $$即使在管道命令列表中仍然报告相同的PID。

问题是:到底如何使用fork()/ waitpid()实现正确的行为?

2 个答案:

答案 0 :(得分:0)

if test-expr1; then
  cmd1; cmd2; cmd3; ...
fi | { cmd4; cmd5; ...; } | cmd6

将在解析树中呈现为:

                                 _______________|
                                /                \
               ________________|___               \
              /                    \               \
          IF__________________      \               \
         /  \                 \      \               \
test-expr1   cmd1; cmd2; cmd3  (nil)  cmd4; cmd5;     cmd6

看着叶子

  1. test-expr1:如果涉及运行命令,则可能会分叉,否则不需要。
  2. cmd1; ...:可能是叉子,除非它们是内部零件。一个分叉的外壳可以按顺序运行这些命令
  3. cmd4; cmd5:可能是fork,除非内部。一个分叉的外壳可以运行这些序列。
  4. cmd6:可能是分叉,除非内部。一个分叉的外壳可以执行此操作。

将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

答案 1 :(得分:0)

这是不正确的,因为即使在管道命令列表中,echo $$仍然报告相同的PID。

这是正确的,并且您检查的方法不正确。来自bash manual

($$)扩展为Shell的进程ID。在()子外壳程序中,它扩展为调用外壳程序的进程ID,而不是子外壳程序。

因此,您检查了调用外壳程序在所有子外壳程序中是否相同。是的。