У меня есть скрипт 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
, disown
them и т. д., как это можно сделать с обычными заданиями. Кроме того, вы не будете уведомлены, когда они были остановлены или завершены.
В сценарии это не имеет абсолютно никакого значения, поскольку сценарии выполняются с отключенным управлением заданиями.
Но если вы хотите передать вывод фонаработана передний планработавинтерактивныйshell, единственное переносимое решение, которое я могу придумать, — это использование именованного канала.
$ mkfifo fifo
$ command | filter1 > fifo & # this is the background job
$ < fifo sed 10q | filter2 # this is the foreground job