【问题标题】:POSIX sh: how do compound commands work with pipes? [closed]POSIX sh:复合命令如何与管道一起使用? [关闭]
【发布时间】:2020-12-14 12:20:43
【问题描述】:

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

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

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

我的第一个猜测是,对于这些“列表”中的每一个,都会创建一个带有单独 PID 的子 shell,它按顺序执行所有命令,但不会阻止 shell 生成其他进程——如果 shell开始等待cmd1 完成。但这是不正确的,因为即使在管道命令列表中,echo $$ 仍会报告相同的 PID。

问题是:fork()/waitpid() 究竟是如何实现正确行为的?

【问题讨论】:

  • 对于{ list; } 没有创建子shell。对于( list ),创建了一个子shell:Command grouping
  • Wrt 这是不正确的,因为 echo $$ 仍然报告相同的 PID,不,你错了。 $ 的值在子 shell 中不会改变。
  • 尽管立即获得了一些支持,但这个问题的范围并不合理。 POSIX sh 针对各种操作系统开发的实现有很多,如何在一个答案中解释每个 shell 如何实现管道?
  • 我明白了,但我仍然不明白这里需要什么样的答案。比如,等待cmd1 完成的是子shell,而不是父shell。除非在后台启动,否则管道确实会阻塞父 shell。除了对您的预测进行此类更正外,我看不出在回答这个问题时还能提供什么。整个问题似乎是基于对我的一连串误解。
  • 您是否尝试过使用set -x 跟踪执行或检查系统调用跟踪工具(如stracetruss)生成的输出?这应该让您对正在发生的事情有所了解。

标签: bash shell sh posix


【解决方案1】:

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

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

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

所以您检查了调用 shell 在所有子 shell 中是否相同。是的。

【讨论】:

    【解决方案2】:
    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; ...:可能是叉子,除非它们是内部的。一个分叉的 shell 可以按顺序运行这些
    3. cmd4; cmd5:可能分叉,除非内部。一个分叉的 shell 可以运行这些序列。
    4. 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
    

    【讨论】:

    • ps echo 通常是内置的,但 /bin/echo 不是。
    猜你喜欢
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多