Tengo un script bash llamado test.sh
a continuación:
#!/bin/bash
while :
do
echo xxx
sleep 1
done
No sé por qué ./test.sh & | ./test.sh
me da error: -bash: syntax error near unexpected token |'
, mientras que ./test.sh | ./test.sh
y ./test.sh | ./test.sh &
funcionan.
Respuesta1
Eso simplemente no está permitido por el caparazón.gramá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 cómo &
or ;
solo puede terminar listas, y las listas son solo parte de un comando_completo, que no puede ser parte de otras producciones.
Eso es sólo una peculiaridad gramatical; así como { foo & }
es semánticamente similar a foo &
(las llaves, a diferencia de los paréntesis, solo se usan para agrupar comandos, no crean por sí mismas un subshell ni ningún tipo de alcance), puedes considerar { foo & } | bar
que es semánticamente similar a foo & | bar
, si este último estuviera permitido por la gramática.
Entonces la solución para tu ejemplo es simplemente:
{ ./test.sh & } | ./test.sh
Si lo ejecuta desde un shell interactivo, observe que el &
testamentonocrear untrabajo de fondo, pero simplemente ejecute el comando de forma asincrónica, porque el lado derecho de una canalización siempre se ejecuta en un subshell y los comandos de un subshell se ejecutan con el control de trabajo deshabilitado.
Esto es similar a:
(sleep 3600 &)
Las listas asincrónicas (comandos terminados en &
) en un subshell se ejecutan con su entrada estándar redirigida /dev/null
y sus señales SIGINT
y SIGQUIT
ignoradas. Continuarán ejecutándose en segundo plano, pero no podrá ponerlos en primer plano con fg
, disown
etc., como puede hacer con los trabajos normales. Además, no se le notificará cuando fueron detenidos o cancelados.
En un script esto no supone ninguna diferencia, ya que los scripts se ejecutan con el control de trabajo desactivado.
Pero si desea canalizar la salida de un fondotrabajoa un primer planotrabajoen uninteractivoshell, la única solución portátil que se me ocurre es utilizar una canalización con nombre.
$ mkfifo fifo
$ command | filter1 > fifo & # this is the background job
$ < fifo sed 10q | filter2 # this is the foreground job