Yves Asked: 2019-06-07 18:50:39 +0800 CST2019-06-07 18:50:39 +0800 CST 2019-06-07 18:50:39 +0800 CST 为什么是`test.sh & | test.sh` 错误 772 我有一个名为test.sh如下的 bash 脚本: #!/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 &。 bash pipe 1 个回答 Voted Best Answer mosvy 2019-06-08T17:28:51+08:002019-06-08T17:28:51+08:00 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 中的异步列表(以 终止的命令&)在运行时将其标准输入重定向自并忽略/dev/null其SIGINT和信号。SIGQUIT它们将继续在后台运行,但您无法使用fg、disown它们等将它们带到前台,就像您对常规作业所做的那样。此外,当它们停止或终止时,您不会收到通知。 在脚本中这完全没有区别,因为脚本是在禁用作业控制的情况下运行的。 但是,如果您想将后台作业的输出通过管道传输到交互式shell 中的前台作业,我能想到的唯一可移植解决方案是使用命名管道。 $ mkfifo fifo $ command | filter1 > fifo & # this is the background job $ < fifo sed 10q | filter2 # this is the foreground job
shell的语法根本不允许这样做:
请注意如何
&
或;
只能终止列表,并且列表只是 complete_command 的一部分,它不能是其他产生式的一部分。这只是一个语法怪癖。正如
{ foo & }
在语义上类似于foo &
(大括号与括号不同,仅用于对命令进行分组,它们不会自己创建子shell或任何类型的范围),如果允许后者,您可以认为{ foo & } | bar
在语义上类似于foo & | bar
由语法。因此,您的示例的解决方法就是:
如果您从交互式 shell 运行它,请注意
&
不会创建后台作业,而只是异步运行命令,因为管道的右侧始终在子 shell 中运行,并且来自子 shell 的命令与作业一起运行控制禁用。这类似于:
子shell 中的异步列表(以 终止的命令
&
)在运行时将其标准输入重定向自并忽略/dev/null
其SIGINT
和信号。SIGQUIT
它们将继续在后台运行,但您无法使用fg
、disown
它们等将它们带到前台,就像您对常规作业所做的那样。此外,当它们停止或终止时,您不会收到通知。在脚本中这完全没有区别,因为脚本是在禁用作业控制的情况下运行的。
但是,如果您想将后台作业的输出通过管道传输到交互式shell 中的前台作业,我能想到的唯一可移植解决方案是使用命名管道。