我有一个 bash 脚本,名称test.sh
如下:
#!/bin/bash
while :
do
echo xxx
sleep 1
done
我不知道为什么./test.sh & | ./test.sh
给我一个错误:-bash: syntax error near unexpected token |'
,而./test.sh | ./test.sh
和./test.sh | ./test.sh &
工作。
答案1
shell 根本不允许这样做语法:
%start complete_command %% complete_command : list separator | list ; list : list separator_op and_or | and_or ; ... pipe_sequence : command | pipe_sequence '|' linebreak command ; ... separator_op : '&' | ';' ;
请注意如何&
或;
只能终止列表,并且列表只是complete_command的一部分,而不能是其他产生式的一部分。
这只是一个语法上的怪癖;正如{ foo & }
在语义上类似于foo &
(大括号与圆括号不同,仅用于对命令进行分组,它们本身不会创建子shell或任何类型的范围),如果允许后者,您可以认为{ foo & } | bar
在语义上类似于foo & | bar
通过语法。
所以你的例子的解决方法就是:
{ ./test.sh & } | ./test.sh
如果您从交互式 shell 运行它,请&
注意不是创建一个后台工作,但只需异步运行命令,因为管道的右侧始终在子 shell 中运行,并且子 shell 中的命令在禁用作业控制的情况下运行。
这类似于:
(sleep 3600 &)
子 shell 中的异步列表(以 终止的命令&
)运行时,它们的 stdin 被重定向/dev/null
,并且它们的SIGINT
和SIGQUIT
信号被忽略。它们将继续在后台运行,但您不能像处理常规作业那样使用 、they 等fg
将它们带到前台。disown
此外,当它们被停止或终止时,您也不会收到通知。
在脚本中,这绝对没有区别,因为脚本是在禁用作业控制的情况下运行的。
但是如果你想通过管道输出背景工作到前台工作在一个交互的shell,我能想到的唯一可移植的解决方案是使用命名管道。
$ mkfifo fifo
$ command | filter1 > fifo & # this is the background job
$ < fifo sed 10q | filter2 # this is the foreground job