it-swarm.com.de

Was sind die Steuerungs- und Umleitungsoperatoren der Shell?

Ich sehe oft Online-Tutorials, die verschiedene Befehle mit verschiedenen Symbolen verbinden. Zum Beispiel:

command1 |  command2
command1 &  command2
command1 || command2    
command1 && command2

Andere scheinen Befehle mit Dateien zu verbinden:

command1  > file1
command1  >> file1

Was sind diese Dinge? Wie werden sie genannt? Was machen Sie? Gibt es noch mehr davon?


Meta-Thread zu dieser Frage. .

278
terdon

Diese werden Shell-Operatoren genannt, und ja, es gibt noch mehr davon. Ich werde einen kurzen Überblick über die häufigsten der beiden Hauptklassen Steueroperatoren und mleitungsoperatoren geben und wie sie in Bezug auf die Bash-Shell funktionieren.

A. Bediener steuern

In der Shell-Befehlssprache ein Token, das eine Steuerfunktion ausführt.
Es ist eines der folgenden Symbole:

&   &&   (   )   ;   ;;   <newline>   |   ||

Und |& In Bash.

Ein ! Ist kein Steuerungsoperator, sondern ein Reserved Word . Es wird zu einem logischen NOT [Negationsoperator] innerhalb von Arithmetic Expressions und innerhalb von Testkonstrukten (wobei immer noch ein Leerzeichen erforderlich ist).

A.1 Terminatoren auflisten

  • ;: Führt einen Befehl aus, nachdem ein anderer beendet wurde, unabhängig vom Ergebnis des ersten.

    command1 ; command2
    

    Zuerst wird command1 Im Vordergrund ausgeführt, und sobald es beendet ist, wird command2 Ausgeführt.

    Eine neue Zeile, die nicht in einem Zeichenfolgenliteral oder nach bestimmten Schlüsselwörtern steht, entspricht nicht dem Semikolonoperator. Eine Liste von ; Getrennten einfachen Befehlen ist immer noch eine Liste - wie im Parser der Shell muss weiterhin die einfachen Befehle eingelesen werden, die auf ein ; Getrennt folgen einfacher Befehl vor der Ausführung, während eine neue Zeile eine gesamte Befehlsliste - oder eine Liste von Listen - begrenzen kann. Der Unterschied ist subtil, aber kompliziert: Da die Shell keine vorherige Notwendigkeit zum Einlesen von Daten nach einer neuen Zeile hat, markiert die neue Zeile einen Punkt, an dem die Shell beginnen kann, die einfachen Befehle auszuwerten, die sie bereits eingelesen hat, während ein ; Semikolon nicht.

  • &: Hiermit wird im Hintergrund ein Befehl ausgeführt, mit dem Sie in derselben Shell weiterarbeiten können.

     command1 & command2
    

    Hier wird command1 Im Hintergrund gestartet und command2 Wird sofort im Vordergrund ausgeführt, ohne auf das Beenden von command1 Zu warten.

    Ein Zeilenumbruch nach command1 Ist optional.

A.2 Logische Operatoren

  • &&: Zum Erstellen von UND-Listen können Sie einen Befehl nur ausführen, wenn ein anderer erfolgreich beendet wurde.

     command1 && command2
    

    Hier wird command2 Nach Beendigung von command1 Und nur ausgeführt, wenn command1 Erfolgreich war (wenn der Exit-Code 0 war). Beide Befehle werden im Vordergrund ausgeführt.

    Dieser Befehl kann auch geschrieben werden

    if command1
    then command2
    else false
    fi
    

    oder einfach if command1; then command2; fi, wenn der Rückgabestatus ignoriert wird.

  • ||: Wird zum Erstellen von OR Listen) verwendet. Sie können einen Befehl nur ausführen, wenn ein anderer nicht erfolgreich beendet wurde.

     command1 || command2
    

    Hier wird command2 Nur ausgeführt, wenn command1 Fehlgeschlagen ist (wenn ein anderer Exit-Status als 0 zurückgegeben wurde). Beide Befehle werden im Vordergrund ausgeführt.

    Dieser Befehl kann auch geschrieben werden

    if command1
    then true
    else command2
    fi
    

    oder kürzer if ! command1; then command2; fi.

    Beachten Sie, dass && Und || Linksassoziativ sind. Weitere Informationen finden Sie unter Vorrang der logischen Shell-Operatoren &&, .

  • !: Dies ist ein reserviertes Wort, das als "nicht" -Operator fungiert (aber ein Trennzeichen haben muss), mit dem der Rückgabestatus eines Befehls negiert wird. Geben Sie 0 zurück, wenn der Befehl einen Status ungleich Null zurückgibt. Geben Sie 1 zurück wenn es den Status 0 zurückgibt. Auch ein logisches NICHT für das Dienstprogramm test.

    ! command1
    
    [ ! a = a ]
    

    Und ein echter NOT-Operator in Arithmetic Expressions:

    $ echo $((!0)) $((!23))
    1 0
    

A.3 Rohrbetreiber

  • |: Der Pipe-Operator übergibt die Ausgabe eines Befehls als Eingabe an einen anderen. Ein vom Pipe-Operator erstellter Befehl heißt Pipeline .

     command1 | command2
    

    Jede von command1 Gedruckte Ausgabe wird als Eingabe an command2 Übergeben.

  • |&: Dies ist eine Abkürzung für 2>&1 | In bash und zsh. Es übergibt sowohl die Standardausgabe als auch den Standardfehler eines Befehls als Eingabe an einen anderen.

    command1 |& command2
    

A.4 Andere Listeninterpunktion

;; Wird ausschließlich verwendet, um das Ende einer case-Anweisung zu markieren. Ksh, bash und zsh unterstützen auch ;&, Um zum nächsten Fall durchzufallen, und ;;& (Nicht in ATT ksh), um fortzufahren und nachfolgende Fälle zu testen.

( Und ) Werden verwendet, um Gruppenbefehle und sie in einer Subshell zu starten. { Und } Gruppieren ebenfalls Befehle, starten sie jedoch nicht in einer Subshell. Unter diese Antwort finden Sie eine Erläuterung der verschiedenen Arten von Klammern, Klammern und Klammern in der Shell-Syntax.

B. Umleitungsoperatoren

mleitungsoperator

In der Shell-Befehlssprache ein Token, das eine Umleitungsfunktion ausführt. Es ist eines der folgenden Symbole:

<     >     >|     <<     >>     <&     >&     <<-     <>

Mit diesen können Sie die Ein- und Ausgabe Ihrer Befehle steuern. Sie können an einer beliebigen Stelle innerhalb eines einfachen Befehls erscheinen oder einem Befehl folgen. Weiterleitungen werden in der Reihenfolge verarbeitet, in der sie angezeigt werden, von links nach rechts.

  • <: Gibt eine Eingabe für einen Befehl.

    command < file.txt
    

    Das obige wird command für den Inhalt von file.txt Ausführen.

  • <>: Wie oben, aber die Datei ist im Modus Lesen + Schreiben anstelle von Nur Lesen geöffnet.

    command <> file.txt
    

    Wenn die Datei nicht vorhanden ist, wird sie erstellt.

    Dieser Operator wird selten verwendet, da Befehle im Allgemeinen nur read von ihrem Standard aus es kann in einer Reihe spezifischer Situationen nützlich sein .

  • >: Leitet die Ausgabe eines Befehls in eine Datei.

    command > out.txt
    

    Das obige speichert die Ausgabe von command als out.txt. Wenn die Datei vorhanden ist, wird ihr Inhalt überschrieben und wenn sie nicht vorhanden ist, wird sie erstellt.

    Dieser Operator wird auch häufig verwendet, um zu wählen, ob etwas auf Standardfehler oder Standardausgabe gedruckt werden soll:

    command >out.txt 2>error.txt
    

    Im obigen Beispiel leitet > Die Standardausgabe um und 2> Leitet den Standardfehler um. Die Ausgabe kann auch mit 1> Umgeleitet werden. Da dies jedoch die Standardeinstellung ist, wird 1 Normalerweise weggelassen und einfach als > Geschrieben.

    Um also command auf file.txt Auszuführen und die Ausgabe in out.txt Und alle Fehlermeldungen in error.txt Zu speichern, würden Sie Folgendes ausführen:

    command < file.txt > out.txt 2> error.txt
    
  • >|: Entspricht >, Überschreibt jedoch das Ziel, auch wenn die Shell so konfiguriert wurde, dass das Überschreiben verweigert wird (mit set -C Oder set -o noclobber). .

    command >| out.txt
    

    Wenn out.txt Existiert, ersetzt die Ausgabe von command den Inhalt. Wenn es nicht existiert, wird es erstellt.

  • >>: Entspricht >, Nur dass die neuen Daten angehängt werden, wenn die Zieldatei vorhanden ist.

    command >> out.txt
    

    Wenn out.txt Existiert, wird die Ausgabe von command an das angehängt, nachdem was bereits darin enthalten ist. Wenn es nicht existiert, wird es erstellt.

  • &>, >&, >>& Und &>>: (Nicht standardisiert). Leiten Sie sowohl den Standardfehler als auch die Standardausgabe um, indem Sie sie ersetzen bzw. anhängen.

    command &> out.txt
    

    Sowohl der Standardfehler als auch die Standardausgabe von command werden in out.txt Gespeichert, wobei der Inhalt überschrieben oder erstellt wird, wenn er nicht vorhanden ist.

    command &>> out.txt
    

    Wie oben, außer dass, wenn out.txt Existiert, die Ausgabe und der Fehler von command daran angehängt werden.

    Die Variante &> Stammt aus bash, während die Variante >& Von csh stammt (Jahrzehnte zuvor). Beide stehen in Konflikt mit anderen POSIX-Shell-Operatoren und sollten nicht in portablen sh -Skripten verwendet werden.

  • <<: Ein hier Dokument. Es wird häufig zum Drucken mehrzeiliger Zeichenfolgen verwendet.

     command << Word
         Text
     Word
    

    Hier nimmt command alles, bis das nächste Vorkommen von Word, Text im obigen Beispiel als Eingabe gefunden wird. Während Word häufig EoF oder Variationen davon ist, kann es sich um eine beliebige alphanumerische Zeichenfolge (und nicht nur) handeln. Wenn Word in Anführungszeichen gesetzt wird, wird der Text im Dokument hier wörtlich behandelt und es werden keine Erweiterungen durchgeführt (z. B. für Variablen). Wenn es nicht in Anführungszeichen steht, werden Variablen erweitert. Weitere Informationen finden Sie im Bash-Handbuch .

    Wenn Sie die Ausgabe von command << Word ... Word Direkt in einen anderen Befehl oder andere Befehle leiten möchten, müssen Sie die Pipe in dieselbe Zeile wie << Word Setzen. Sie können sie nicht nach dem abschließenden Word oder setzen in der folgenden Zeile. Zum Beispiel:

     command << Word | command2 | command3...
         Text
     Word
    
  • <<<: Hier Zeichenfolgen, ähnlich wie hier Dokumente, aber für eine einzelne Zeile vorgesehen. Diese existieren nur im Unix-Port oder rc (wo er entstanden ist), zsh, einigen Implementierungen von ksh, yash und bash.

    command <<< Word
    

    Was auch immer als Word angegeben ist, wird erweitert und sein Wert wird als Eingabe an command übergeben. Dies wird häufig verwendet, um den Inhalt von Variablen als Eingabe an einen Befehl zu übergeben. Zum Beispiel:

     $ foo="bar"
     $ sed 's/a/A/' <<< "$foo"
     bAr
     # as a short-cut for the standard:
     $ printf '%s\n' "$foo" | sed 's/a/A/'
     bAr
     # or
     sed 's/a/A/' << EOF
     $foo
     EOF
    

Einige andere Operatoren (>&-, x>&yx<&y) Können zum Schließen oder Duplizieren von Dateideskriptoren verwendet werden. Einzelheiten dazu finden Sie im entsprechenden Abschnitt des Handbuchs Ihrer Shell ( hier zum Beispiel für Bash).

Dies gilt nur für die häufigsten Betreiber von Bourne-ähnlichen Schalen. Einige Shells verfügen über einige zusätzliche eigene Umleitungsoperatoren.

Ksh, bash und zsh haben auch Konstrukte <(…), >(…) und =(…) (das letztere nur in zsh). Dies sind keine Umleitungen, sondern Prozessersetzung .

381
terdon

Warnung bezüglich ">"

Unix-Anfänger, die gerade etwas über die E/A-Umleitung gelernt haben (< Und >), Versuchen häufig Dinge wie

befehl … eingabedatei > the_same_file

oder

befehl … < datei     > the_same_file

oder fast gleichwertig

katze datei | befehl …> the_same_file

(grep, sed, cut, sort und spell sind Beispiele für Befehle, die Menschen in Konstrukten wie diesen verwenden möchten .) Benutzer sind überrascht festzustellen, dass diese Szenarien dazu führen, dass die Datei leer wird.

Eine Nuance, die in der anderen Antwort nicht erwähnt zu werden scheint, lauert im ersten Satz des Abschnitts Redirection von bash (1) :

Bevor ein Befehl ausgeführt wird, kann seine Eingabe und Ausgabe umgeleitet Unter Verwendung einer von der Shell interpretierten speziellen Notation erfolgen.

Die ersten fünf Wörter sollten fett, kursiv, unterstrichen, vergrößert, blinkend, rot gefärbt und mit a gekennzeichnet sein exclamation mark in red triangle Symbol, um die Tatsache hervorzuheben, dass die Shell die angeforderte (n) Umleitung (en) ausführt bevor der Befehl ausgeführt wird. Und denk auch daran

Durch die Umleitung der Ausgabe wird die Datei… zum Schreiben geöffnet…. Wenn die Datei nicht vorhanden ist, wird sie erstellt. Wenn es existiert, wird es auf die Größe Null abgeschnitten.

  1. Also in diesem Beispiel:

    sort roster > roster
    

    die Shell öffnet die Datei roster zum Schreiben und schneidet sie ab (d. h. verwirft ihren gesamten Inhalt), bevor das Programm sort ausgeführt wird. Natürlich kann nichts unternommen werden, um die Daten wiederherzustellen.

  2. Das könnte man naiv erwarten

    tr "[:upper:]" "[:lower:]" < poem > poem
    

    könnte besser sein. Da die Shell Umleitungen von links nach rechts verarbeitet, öffnet sie poem zum Lesen (für die Standardeingabe von tr), bevor sie zum Schreiben (für die Standardausgabe) geöffnet wird. Aber es hilft nicht. Obwohl diese Abfolge von Operationen zwei Dateihandles ergibt, zeigen beide auf dieselbe Datei. Wenn die Shell die Datei zum Lesen öffnet, ist der Inhalt immer noch vorhanden, aber er wird immer noch überlastet, bevor das Programm ausgeführt wird.

Also, was tun?

Lösungen umfassen:

  • Überprüfen Sie, ob das von Ihnen ausgeführte Programm über eine eigene interne Funktion verfügt, mit der angegeben werden kann, wohin die Ausgabe geleitet wird. Dies wird häufig durch ein Token -o (Oder --output=) Angezeigt. Bestimmtes,

    sort roster -o roster
    

    ist ungefähr gleichbedeutend mit

    sort roster > roster
    

    außer im ersten Fall öffnet das Programm sort die Ausgabedatei. Und es ist klug genug, die Ausgabedatei erst zu öffnen, wenn after alle Eingabedateien gelesen hat.

    Ebenso haben zumindest einige Versionen von sed einen -i (Bearbeiten ichn place) Option, mit der die Ausgabe wieder in die Eingabedatei geschrieben werden kann (wieder after alle Eingaben wurden gelesen). Editoren wie ed/ex, emacs, pico und vi/vim ermöglichen dem Benutzer das Bearbeiten von a Textdatei und speichern Sie den bearbeiteten Text in der Originaldatei. Beachten Sie, dass ed (zumindest) nicht interaktiv verwendet werden kann.

    • vi hat eine verwandte Funktion. Wenn Sie :%!command EingebenEnterwird der Inhalt des Bearbeitungspuffers in command geschrieben, die Ausgabe gelesen und in den Puffer eingefügt (wobei der ursprüngliche Inhalt ersetzt wird).
  • Einfach aber effektiv:

    befehl … eingabedatei > temp_file  && mv temp_fileeingabedatei

    Dies hat den Nachteil, dass wenn input_file ein Link ist, dieser (wahrscheinlich) durch eine separate Datei ersetzt wird. Außerdem gehört die neue Datei Ihnen mit Standardschutz. Dies birgt insbesondere das Risiko, dass die Datei weltweit lesbar ist, auch wenn das Original input_file nicht vorhanden war.

    Variationen:

    • commandinput_file > temp_file && cp temp_fileinput_file && rm temp_file
      , der (möglicherweise) immer noch den temp_file weltlesbar lässt. Noch besser:
    • cp input_filetemp_file && commandtemp_file > input_file && rm temp_file
      Diese behalten den Verbindungsstatus, den Eigentümer und den Modus (Schutz) der Datei bei, möglicherweise auf Kosten von doppelt so viel E/A. (Möglicherweise müssen Sie eine Option wie -a Oder -p Für cp verwenden, um anzuweisen, dass Attribute beibehalten werden sollen.)
    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_filetemp_file &&
      mv temp_fileinput_file
      (nur zur besseren Lesbarkeit in separate Zeilen unterteilt) Dadurch wird der Modus der Datei (und, wenn Sie root sind, der Eigentümer) beibehalten, aber sie gehört Ihnen (wenn Sie nicht root sind) und macht es zu einer neuen, separaten Datei.
  • Dieser Blog ("In-Place" -Bearbeitung von Dateien) schlägt vor und erklärt

    {rm eingabedatei  && befehl …> eingabedatei;; } < eingabedatei

    Dies erfordert, dass command Standardeingaben verarbeiten kann (aber fast alle Filter können). Der Blog selbst nennt dies einen riskanten Kludge und rät von seiner Verwendung ab. Dadurch wird auch eine neue, separate Datei erstellt (die mit nichts verknüpft ist), die Ihnen gehört und über Standardberechtigungen verfügt.

  • Das moreutils-Paket hat einen Befehl namens sponge:

    befehl … eingabedatei | Schwamm the_same_file

    Siehe diese Antwort für weitere Informationen.

Folgendes hat mich völlig überrascht: Syntaxfehler sagt :

[Die meisten dieser Lösungen] schlagen in einem schreibgeschützten Dateisystem fehl, wobei "schreibgeschützt" bedeutet, dass Ihr $HOME wird beschreibbar ist, aber /tmp ist schreibgeschützt (standardmäßig). Wenn Sie beispielsweise Ubuntu haben und die Wiederherstellungskonsole gestartet haben, ist dies häufig der Fall. Auch der Here-Document-Operator <<< Funktioniert dort nicht, da /tmp gelesen/geschrieben werden muss , weil dort auch eine temporäre Datei geschrieben wird.
(Vgl. diese Frage enthält eine strace ’d Ausgabe)

In diesem Fall kann Folgendes funktionieren:

  • Nur für fortgeschrittene Benutzer: Wenn Ihr Befehl garantiert die gleiche Menge an Ausgabedaten erzeugt, wie eingegeben wird (z. B. sort, oder tr ohne die Option -d oder -s), können Sie versuchen.
    befehl … eingabedatei | dd von =the_same_file conv = notrunc
    Weitere Informationen, einschließlich einer Erläuterung der oben genannten Punkte, und Alternativen, die funktionieren, wenn Ihr Befehl garantiert dieselbe Menge produziert, finden Sie unter diese Antwort und diese Antwort von Ausgabedaten bei Eingabe oder weniger (z. B. grep oder cut). Diese Antworten haben den Vorteil, dass sie keinen freien Speicherplatz benötigen (oder sehr wenig). Die obigen Antworten des Formulars commandinput_file > temp_file && … Erfordern eindeutig, dass genügend freier Speicherplatz vorhanden ist, damit das System die gesamte (alte) Eingabe- und (neue) Ausgabedatei gleichzeitig speichern kann. Dies gilt nicht offensichtlich auch für die meisten anderen Lösungen (z. B. sed -i und sponge). Ausnahme: sort … | dd … Benötigt wahrscheinlich viel freien Speicherplatz, da sort alle Eingaben lesen muss, bevor eine Ausgabe geschrieben werden kann, und wahrscheinlich die meisten, wenn nicht alle dieser Daten in a puffert temporäre Datei.
  • Nur für fortgeschrittene Benutzer:
    befehl … eingabedatei 1 <> the_same_file
    kann der obigen Antwort dd entsprechen. Die Syntax n<>file Öffnet die benannte Datei im Dateideskriptor n für Eingabe und Ausgabe, ohne sie abzuschneiden - sortieren einer Kombination von n< und n>. Hinweis: Einige Programme (z. B. cat und grep) können in diesem Szenario möglicherweise nicht ausgeführt werden, da sie erkennen können, dass die Eingabe und die Ausgabe dieselbe Datei sind. Siehe diese Antwort für eine Diskussion der oben genannten Punkte und ein Skript, mit dem diese Antwort funktioniert, wenn Ihr Befehl garantiert die gleiche Menge an Ausgabedaten erzeugt wie Eingaben oder weniger.
    Warnung: Ich habe Peters Skript nicht getestet, deshalb bürge ich nicht dafür.

Also, was war die Frage?

Dies war ein beliebtes Thema bei U & L; es wird in den folgenden Fragen angesprochen:

… Und das gilt nicht für Super User oder Ask Ubuntu. Ich habe viele Informationen aus den Antworten auf die obigen Fragen hier in diese Antwort aufgenommen, aber nicht alle. (Weitere Informationen finden Sie in den oben aufgeführten Fragen und deren Antworten.)

P.S. Ich habe keine Zugehörigkeit zu dem Blog, das ich oben zitiert habe.

64
Scott

Weitere Beobachtungen zu ;, &, ( Und )

  • Beachten Sie, dass einige der Befehle in Terdons Antwort möglicherweise null sind. Zum Beispiel kann man sagen

    command1 ;
    

    (ohne command2). Dies entspricht

    command1
    

    (d. h. es läuft einfach command1 im Vordergrund und wartet darauf, dass es abgeschlossen ist.

    command1 &
    

    (ohne command2) startet command1 im Hintergrund und gibt dann sofort eine weitere Shell-Eingabeaufforderung aus.

  • Im Gegensatz dazu ergeben command1 &&, command1 || Und command1 | Keinen Sinn. Wenn Sie eine davon eingeben, geht die Shell (wahrscheinlich) davon aus, dass der Befehl in einer anderen Zeile fortgesetzt wird. Es wird die sekundäre (Fortsetzung) Shell-Eingabeaufforderung angezeigt, die normalerweise auf > Eingestellt ist, und weiter gelesen. In einem Shell-Skript liest es einfach die nächste Zeile und hängt sie an das an, was es bereits gelesen hat. (Achtung: Dies ist möglicherweise nicht das, was Sie möchten.)

    Hinweis: Einige Versionen einiger Shells behandeln unvollständige Befehle möglicherweise als Fehler. In solchen Fällen (oder sogar in einem beliebigen Fall, in dem Sie einen langen Befehl haben) können Sie einen Backslash (\) Am Ende einer Zeile einfügen, um die Shell zu informieren So lesen Sie den Befehl in einer anderen Zeile weiter:

    command1  &&  \
    command2
    

    oder

    find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
                            -newer some_existing_file -user fred -readable -print
    
  • Wie Terdon sagt, können ( Und ) Zum Gruppieren von Befehlen verwendet werden. Die Aussage, dass sie für diese Diskussion „nicht wirklich relevant“ sind, ist umstritten. Einige der Befehle in Terdons Antwort könnten Befehl Gruppen sein. Zum Beispiel,

    ( command1 ; command2 )  &&  ( command3; command4 )
    

    macht dies:

    • Führen Sie command1 Aus und warten Sie, bis der Vorgang abgeschlossen ist.
    • Führen Sie dann unabhängig vom Ergebnis der Ausführung dieses ersten Befehls command2 Aus und warten Sie, bis der Vorgang abgeschlossen ist.
    • Wenn dann command2 Erfolgreich war,

      • Führen Sie command3 Aus und warten Sie, bis der Vorgang abgeschlossen ist.
      • Führen Sie dann unabhängig vom Ergebnis der Ausführung dieses Befehls command4 Aus und warten Sie, bis der Befehl abgeschlossen ist.

      Wenn command2 Fehlgeschlagen ist, beenden Sie die Verarbeitung der Befehlszeile.

  • Außerhalb von Klammern bindet | Sehr eng

    command1 | command2 || command3
    

    ist äquivalent zu

    ( command1 | command2 )  ||  command3
    

    und && und || binden enger als ;

    command1 && command2 ; command3
    

    ist äquivalent zu

    ( command1 && command2 ) ;  command3
    

    d.h. command3 wird unabhängig vom Exit-Status von command1 und/oder command2 ausgeführt.