Ich habe ein Bash-Skript mit test.sh
dem folgenden Namen:
#!/bin/bash
while :
do
echo xxx
sleep 1
done
Ich weiß nicht, warum ./test.sh & | ./test.sh
mir ein Fehler angezeigt wird: -bash: syntax error near unexpected token |'
, während ./test.sh | ./test.sh
und ./test.sh | ./test.sh &
funktionieren.
Antwort1
Das ist einfach nicht erlaubt durch die ShellGrammatik:
%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 : '&' | ';' ;
Beachten Sie, dass &
oder ;
nur Listen beenden kann und Listen nur Teil eines Complete_Commands sind, der nicht Teil anderer Produktionen sein kann.
Das ist nur eine grammatikalische Eigenart. Genauso wie { foo & }
semantisch ähnlich zu ist foo &
(die Klammern werden im Gegensatz zu runden Klammern nur zum Gruppieren von Befehlen verwendet, sie erstellen selbst weder eine Untershell noch irgendeine Art von Bereich), können Sie es { foo & } | bar
als semantisch ähnlich zu betrachten foo & | bar
, wenn Letzteres von der Grammatik zugelassen würde.
Der Workaround für Ihr Beispiel ist also einfach:
{ ./test.sh & } | ./test.sh
Wenn Sie das von einer interaktiven Shell aus ausführen, beachten Sie, dass der &
Willenichtein ... kreierenHintergrundjob, sondern führen Sie den Befehl einfach asynchron aus, da die rechte Seite einer Pipeline immer in einer Subshell ausgeführt wird und die Befehle aus einer Subshell mit deaktivierter Jobsteuerung ausgeführt werden.
Dies ist ähnlich wie:
(sleep 3600 &)
Die asynchronen Listen (Befehle, die durch beendet werden &
) in einer Subshell werden mit ihrer Standardeingabe umgeleitet /dev/null
und ihre SIGINT
und SIGQUIT
Signale werden ignoriert. Sie werden weiterhin im Hintergrund ausgeführt, aber Sie können sie nicht mit fg
, disown
them usw. in den Vordergrund holen, wie Sie es bei regulären Jobs tun können. Außerdem werden Sie nicht benachrichtigt, wenn sie gestoppt oder beendet wurden.
In einem Skript macht dies absolut keinen Unterschied, da Skripte mit deaktivierter Jobsteuerung ausgeführt werden.
Wenn Sie aber die Ausgabe eines Hintergrunds weiterleiten möchtenArbeitin den VordergrundArbeitin einem (ninteraktivShell, die einzige portable Lösung, die mir einfällt, ist die Verwendung einer benannten Pipe.
$ mkfifo fifo
$ command | filter1 > fifo & # this is the background job
$ < fifo sed 10q | filter2 # this is the foreground job