`shopt -s lastpipe` 如何影响 bash 脚本行为?

Shu*_*man 6 bash shell

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

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

shopt -s extglob lastpipe
Run Code Online (Sandbox Code Playgroud)

lastpipe 选项仅在 bash 4.3 之后可用,我该怎么做才能模拟它的效果?

kyb*_*kyb 9

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

echo asd | var=$(cat) ; echo $var
Run Code Online (Sandbox Code Playgroud)

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

man bash

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

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

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

所以

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

现在var包含asd.

谢谢@chepner。


早些时候我曾经这样写:

{ while read;do var="$REPLY";done; } < <(command | filter)
Run Code Online (Sandbox Code Playgroud)

在情况下

var=$(command | filter)
Run Code Online (Sandbox Code Playgroud)

不适合。


che*_*ner 8

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

# foo | bar | baz becomes ...
baz < <(foo | bar)
Run Code Online (Sandbox Code Playgroud)

或命名管道(也符合 POSIX 标准)

# foo | bar | baz becomes ...
mkfifo baz_input
foo | bar > baz_input &
baz < baz_input
Run Code Online (Sandbox Code Playgroud)

  • 这是因为您处于一个交互式 shell 中,并且作业控制处于活动状态;需要停用作业控制(出于我一直不太理解的原因)才能使“lastpipe”生效。如果您将该代码放入脚本中,您将看到“lastpiped”版本确实在调用之间增加了“i”。(您还可以使用“set +m”在交互式 shell 中禁用作业控制。) (3认同)