почему `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

Это просто не допускается оболочкой.грамматика:

%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 &(фигурные скобки, в отличие от круглых, используются только для группировки команд, они сами по себе не создают подоболочку или какую-либо область действия), можно считать { foo & } | barсемантически похожим на foo & | bar, если бы последнее допускалось грамматикой.

Итак, обходной путь для вашего примера такой:

{ ./test.sh & } | ./test.sh

Если вы запустите это из интерактивной оболочки, обратите внимание, что &будетнетсоздатьфоновая работа, а просто запустите команду асинхронно, поскольку правая часть конвейера всегда выполняется в подоболочке, а команды из подоболочки выполняются с отключенным управлением заданиями.

Это похоже на:

(sleep 3600 &)

Асинхронные списки (команды, завершаемые &) в подоболочке запускаются с перенаправлением их stdin /dev/nullи игнорированием их сигналов SIGINTи SIGQUIT. Они продолжат работать в фоновом режиме, но вы не сможете вывести их на передний план с помощью fg, disownthem и т. д., как это можно сделать с обычными заданиями. Кроме того, вы не будете уведомлены, когда они были остановлены или завершены.

В сценарии это не имеет абсолютно никакого значения, поскольку сценарии выполняются с отключенным управлением заданиями.

Но если вы хотите передать вывод фонаработана передний планработавинтерактивныйshell, единственное переносимое решение, которое я могу придумать, — это использование именованного канала.

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

Связанный контент