為什麼是`test.sh & | test.sh`錯誤

為什麼是`test.sh & | test.sh`錯誤

我有一個 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,並且它們的SIGINTSIGQUIT訊號被忽略。它們將繼續在後台運行,但您不能像處理常規作業那樣使用 、they 等fg將它們帶到前台。disown此外,當它們被停止或終止時,您也不會收到通知。

在腳本中,這絕對沒有區別,因為腳本是在停用作業控制的情況下執行的。

但是如果你想透過管道輸出背景工作到前台工作在一個互動的shell,我能想到的唯一可移植的解決方案是使用命名管道。

$ mkfifo fifo
$ command | filter1 > fifo &  # this is the background job
$ < fifo sed 10q | filter2    # this is the foreground job

相關內容