【发布时间】:2019-09-26 13:16:10
【问题描述】:
我正在尝试使 ffcast 屏幕投射工具 bash 4.1 向后兼容。
在这个ffcast.bash 脚本中,有一行
shopt -s extglob lastpipe
lastpipe 选项仅在 bash 4.3 之后可用,如何模拟其效果?
【问题讨论】:
我正在尝试使 ffcast 屏幕投射工具 bash 4.1 向后兼容。
在这个ffcast.bash 脚本中,有一行
shopt -s extglob lastpipe
lastpipe 选项仅在 bash 4.3 之后可用,如何模拟其效果?
【问题讨论】:
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 < <(true); f redirected < <(true) 。无论lastpipe 状态如何,只有重定向的输入才能正确保存递增的计数器。
lastpipe 才能生效。如果您将该代码放入脚本中,您将看到lastpiped 版本确实在调用之间增加i。 (您也可以使用 set +m 在交互式 shell 中禁用作业控制。)
没有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)
不适合。
【讨论】: