Eu tenho um script bash chamado test.sh
abaixo:
#!/bin/bash
while :
do
echo xxx
sleep 1
done
Não sei por que ./test.sh & | ./test.sh
me dá um erro: -bash: syntax error near unexpected token |'
, enquanto ./test.sh | ./test.sh
e ./test.sh | ./test.sh &
funciona.
Responder1
Isso simplesmente não é permitido pelo shellgramática:
%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 : '&' | ';' ;
Observe como &
ou ;
só pode encerrar listas, e as listas são apenas parte de um complete_command, que não pode fazer parte de outras produções.
Isso é apenas uma peculiaridade gramatical; assim como { foo & }
é semanticamente semelhante a foo &
(os colchetes, ao contrário dos parênteses, são usados apenas para agrupar comandos, eles não criam por si só um subshell ou qualquer tipo de escopo), você pode considerar { foo & } | bar
ser semanticamente semelhante a foo & | bar
, se este último fosse permitido pela gramática.
Portanto, a solução alternativa para o seu exemplo é apenas:
{ ./test.sh & } | ./test.sh
Se você executar isso a partir de um shell interativo, observe que &
onãoCrie umtrabalho em segundo plano, mas apenas execute o comando de forma assíncrona, porque o lado direito de um pipeline é sempre executado em um subshell e os comandos de um subshell são executados com o controle de trabalho desabilitado.
Isso é semelhante a:
(sleep 3600 &)
As listas assíncronas (comandos terminados por &
) em um subshell são executadas com seu stdin redirecionado /dev/null
e seus sinais SIGINT
e SIGQUIT
ignorados. Eles continuarão sendo executados em segundo plano, mas você não poderá trazê-los para o primeiro plano com fg
, disown
eles, etc., como faria com trabalhos regulares. Além disso, você não será notificado quando eles forem interrompidos ou encerrados.
Em um script isso não faz absolutamente nenhuma diferença, já que os scripts são executados com o controle de trabalho desabilitado.
Mas se você quiser canalizar a saída de um plano de fundotrabalhopara um primeiro planotrabalhoem uminterativoshell, a única solução portátil que consigo pensar é usar um pipe nomeado.
$ mkfifo fifo
$ command | filter1 > fifo & # this is the background job
$ < fifo sed 10q | filter2 # this is the foreground job