我正在尝试使ffcast屏幕投射工具 bash 4.1 向后兼容。
在这个ffcast.bash脚本中,有一行
shopt -s extglob lastpipe
Run Code Online (Sandbox Code Playgroud)
lastpipe 选项仅在 bash 4.3 之后可用,我该怎么做才能模拟它的效果?
启用和启用作业控制的通常行为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)
不适合。
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)