【问题标题】:how does `shopt -s lastpipe` affect bash script behavior?`shopt -s lastpipe` 如何影响 bash 脚本的行为?
【发布时间】:2019-09-26 13:16:10
【问题描述】:

我正在尝试使 ffcast 屏幕投射工具 bash 4.1 向后兼容。

在这个ffcast.bash 脚本中,有一行

shopt -s extglob lastpipe

lastpipe 选项仅在 bash 4.3 之后可用,如何模拟其效果?

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    lastpipe(顺便说一下,在 bash 4.2 中引入)只能通过不使用管道来模拟。您需要在当前 shell 中显式运行管道的最后一个命令,并从进程替换中重定向其输入

    # foo | bar | baz becomes ...
    baz < <(foo | bar)
    

    或命名管道(也符合 POSIX)

    # foo | bar | baz becomes ...
    mkfifo baz_input
    foo | bar > baz_input &
    baz < baz_input
    

    【讨论】:

    • 那些不相等。此代码显示了不同之处。 i=0; f() { echo "$1: $((i++))"; }; shopt -u lastpipe; true | f piped; true | f piped; shopt -s lastpipe; true | f lastpiped; true | f lastpiped; f redirected &lt; &lt;(true); f redirected &lt; &lt;(true) 。无论lastpipe 状态如何,只有重定向的输入才能正确保存递增的计数器。
    • 那是因为你在一个交互式shell中,作业控制处于活动状态;需要停用作业控制(出于我从未完全理解的原因),lastpipe 才能生效。如果您将该代码放入脚本中,您将看到lastpiped 版本确实在调用之间增加i。 (您也可以使用 set +m 在交互式 shell 中禁用作业控制。)
    • 谢谢!它在脚本中工作。介意在您的答案中添加作业控制和脚本与交互位吗?
    【解决方案2】:

    没有lastpipe 并且启用了作业控制的通常行为是在子shell 中运行管道的每个元素。

    echo asd | var=$(cat) ; echo $var
    

    var 不包含任何内容,但用户可能期望var 将包含asd。这是因为最后一个管道元素将var 设置在一个无法访问当前shell 环境的子shell 中。

    来自man bash

    管道中的每个命令都作为一个单独的进程执行(即在子外壳中)。有关子 shell 环境的描述,请参阅命令执行环境。如果使用启用了 lastpipe 选项 内置 shopt(参见下面对 shopt 的描述),管道的最后一个元素可能由 shell 进程运行。

    我不知道可能是什么... 这是更好的描述:

    lastpipe
    如果设置,并且作业控制未激活,则 shell 将在当前 shell 环境中运行未在后台执行的管道的最后一个命令。

    所以

    set +m  # To disable job control
    shopt -s lastpipe
    echo asd | var=$(cat)
    echo $var
    

    现在var 包含asd

    谢谢@chepner。


    之前我是这样写的:

    { while read;do var="$REPLY";done; } < <(command | filter)
    

    如果

    var=$(command | filter)
    

    不适合。

    【讨论】:

      猜你喜欢
      • 2011-01-04
      • 1970-01-01
      • 2011-09-20
      • 1970-01-01
      • 2018-07-02
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多