por que `test.sh & | test.sh` errado

por que `test.sh & | test.sh` errado

Eu tenho um script bash chamado test.shabaixo:

#!/bin/bash

while :
do
    echo xxx
    sleep 1
done

Não sei por que ./test.sh & | ./test.shme dá um erro: -bash: syntax error near unexpected token |', enquanto ./test.sh | ./test.she ./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 & } | barser 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/nulle seus sinais SIGINTe SIGQUITignorados. Eles continuarão sendo executados em segundo plano, mas você não poderá trazê-los para o primeiro plano com fg, disowneles, 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

informação relacionada