Wie kann ich mehrere Befehle ausführen, die & in einer Befehlszeile haben?

12

Ich habe ein Kopfschmerzproblem festgestellt.

Ich möchte mehrere Befehle im Hintergrund ausführen, also möchte ich sie einzeln in Bash starten. Es ist einfach, einen Befehl in der Linux-Shell im Hintergrund zu starten:

myCommand &

Es ist auch einfach, mehrere Befehle wie folgt zu starten:

myCommand1 && myCommand2

oder

myCommand1 ; myCommand2

Wenn ich jedoch mehrere Befehle im Hintergrund ausführen möchte, habe ich das folgende Befehlsformat ausprobiert, bin jedoch fehlgeschlagen:

myCommand1 & && myCommand2 &

oder

myCommand1 & ; myCommand2 &

Beide Formate schlagen fehl. Wie kann ich mehrere Befehle ausführen, die sich &in einer Befehlszeile befinden?

Uhr ZHONG
quelle
2
Fügen Sie sie in ein Skript ein und führen Sie das Skript im Hintergrund aus
Panther
Panther, es scheint, dass die Verwendung von () dazu beitragen könnte, dieses Problem viel einfacher zu beheben als die Verwendung eines Skripts. Lassen Sie uns zunächst versuchen, die von der Shell selbst bereitgestellten Funktionen vollständig zu nutzen, anstatt selbst zu komponieren, was wir wollen. Aber natürlich kann die Verwendung eines Skripts auch dieses Problem beheben. Danke trotzdem.
Uhr ZHONG
Was ist, wenn ich ein 'tail -F <file1> <file2>' gefolgt von 'jobs -l' ausführen möchte, gefolgt von 'disown -h% 1'
akskap

Antworten:

23

Verwenden ().

Wenn Sie sie nacheinander ausführen möchten:

(myCommand1; myCommand2) &

oder

(myCommand1 &) && (myCommand2 &)

Wenn Sie möchten, dass sie parallel ausgeführt werden:

myCommand1 & myCommand2 &

In bash können Sie dies auch verwenden (Leerzeichen hinter dem {und dem; sind obligatorisch):

{ myCommand1 && myCommand2; } &
Rinzwind
quelle
3
(myCommand1 &) && (myCommand2 &)läuft myCommand2auch wenn myCommand1fehlgeschlagen.
Terdon
() könnte helfen, das & und && zu unterscheiden. Verwenden Sie also einfach (), um die Ausführungseinheit zu trennen, wenn Sie das & und && zusammen verwenden möchten.
Uhr ZHONG
16

Ich nehme an, Sie wollen das:

myCommand1 & myCommand2 &

Dies startet myCommand1und sendet es an den Hintergrund, gefolgt von kaufmännischem Und, startet dann sofort myCommand2und sendet auch dieses an den Hintergrund, wodurch die Shell wieder freigegeben wird.

Listen

Zum besseren Verständnis können Sie die Pipeline hier durch einen Befehl ersetzen .

Eine Liste ist eine Folge von einer oder mehreren Pipelines, die von einem der Operatoren getrennt werden . , & , && oder || und optional beendet durch einen von ; , & , oder .

Wenn ein Befehl vom Steueroperator & beendet wird , führt die Shell den Befehl im Hintergrund in einer Subshell aus. Die Shell wartet nicht auf den Abschluss des Befehls und der Rückgabestatus ist 0. Befehle getrennt durch a ; werden nacheinander ausgeführt; Die Shell wartet darauf, dass jeder Befehl nacheinander beendet wird. Der Rückgabestatus ist der Beendigungsstatus des zuletzt ausgeführten Befehls.

AND- und OR-Listen sind Sequenzen einer oder mehrerer Pipelines, die durch && und || getrennt sind Steueroperatoren.
Quelle:man bash

Lassen Sie uns das in Beispiele zerlegen. Sie können eine Liste erstellen, indem Sie Befehle kombinieren und mit einem der folgenden trennen ; & && ||:

command1 ; command2  # runs sequentially
command1 && command2 # runs sequentially, runs command2 only if command1 succeeds
command1 || command2 # runs sequentially, runs command2 only if command1 fails
command1 & command2  # runs simultaneously

Sie können Listen mit einer der folgenden Optionen beenden : ; & <newline>.
Normalerweise führen Sie einen Befehl oder eine Liste durch Drücken von aus Enter, das entspricht <newline>. Das Semikolon ;dient genau dem gleichen Zweck, insbesondere in Skripten. Das &kaufmännische Und startet die Befehle jedoch in einer Subshell im Hintergrund und gibt die Shell sofort frei.

Sie können runde ()oder geschweifte Klammern verwenden, {}um weitere Gruppenlisten zu erstellen. Der Unterschied besteht darin, dass runde Klammern eine Unterschale erzeugen und geschweifte nicht. Geschweifte Klammern benötigen ein Leerzeichen nach dem ersten und ein Semikolon oder eine neue Zeile vor der schließenden Klammer. Beispielsweise:

# if c1 succeeds start a shell in the background
# and run c2 and c3 sequentially inside it
c1 && ( c2 ; c3 ) & 
# run c1 and if it succeeds c2 sequentially as a group command
# if c1 or c2 fail run c3 in the background
{ c1 && c2 ;} || c3 &

Dies kann ziemlich kompliziert werden, wenn Sie sich nicht sicher sind trueund falsetesten möchten , ob die Konstruktion wie erwartet funktioniert:

$ { true && true ;} || echo 2
$ { true && false ;} || echo 2
2

Auftragssteuerung

Der jobsBefehl zeigt eine Liste der Hintergrundjobs an, die in der aktuellen Shell ausgeführt werden oder kürzlich abgeschlossen wurden. Es gibt eine Reihe von Tastaturkürzeln und Befehlen für die Jobsteuerung:

  • Ctrl+ Zgibt das Suspend- Zeichen ein, das bewirkt, dass der aktuell im Vordergrund ausgeführte Prozess gestoppt wird. Er wird nicht beendet, sondern verbleibt in der jobsListe
  • Ctrl+ Ygibt das verzögerte Suspend- Zeichen ein, das bewirkt, dass der aktuell im Vordergrund ausgeführte Prozess gestoppt wird, wenn versucht wird, Eingaben vom Terminal zu lesen
  • fg= %bringt einen Prozess in den Vordergrund und startet ihn bei Bedarf. Sie können den Prozess wie folgt angeben:

     %       # last process in the jobs list
     %1      # 1st process in the jobs list
     %abc    # process beginning with the string “abc”
     %?abc   # process containing the string “abc” anywhere
  • bg= %&nimmt einen Prozess in den Hintergrund und startet ihn bei Bedarf:

     %&      # last process in the jobs list
     %1&     # 1st process in the jobs list
     %abc&   # process beginning with the string “abc”
     %?abc&  # process containing the string “abc” anywhere
  • wait Wartet auf den Abschluss eines Hintergrundprozesses und gibt seinen Beendigungsstatus zurück:

     wait %1 # 1st process in the jobs list

    Stellen Sie sich vor, Sie haben einen langen Prozess gestartet ( jobszeigt Nummer 3 an) und stellen dann fest, dass der Computer nach Abschluss angehalten werden soll, sowie echoeine Meldung, wenn der Prozess nicht erfolgreich war:

     wait %3 || echo failed ; systemctl suspend
Dessert
quelle
Es ist jedoch wichtig, vorsichtig mit && umzugehen. Dies hängt davon ab, was der Befehl zurückgibt. Daher müssen wir sicher sein, dass alles, was wir aufrufen, tatsächlich etwas zurückgibt, das Bash als wahrheitsgemäßen Wert betrachtet.
Mathreadler
@mathreadler Wenn Sie nicht über ein schlecht gemachtes Benutzerskript sprechen, ist der Exit-Wert sehr gut definiert (siehe man bash) und wird genau so verwendet, wie es beabsichtigt ist. AFAIK - ich habe nie etwas Seltsames erlebt.
Nachtisch
Genau, man sollte vorsichtig sein mit schlecht gemachten Benutzerskripten. Sie existieren und können schmerzhaft sein, solche Fehler zu finden. Askubuntu erlaubt mir nicht, Sie "@ Dessert".
Mathreadler
Ah okay, das macht jetzt Sinn, da Sie es erwähnen.
Mathreadler