Was sind die Steuerungs- und Umleitungsoperatoren der Shell?

245

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. .

terdon
quelle

Antworten:

340

Diese werden als Shell-Operatoren bezeichnet, und es gibt noch mehr davon. Ich gebe einen kurzen Überblick über die häufigsten unter den beiden Hauptklassen, Steuerelementoperatoren und Umleitungsoperatoren , und wie sie in Bezug auf die Bash-Shell funktionieren.

A. Steueroperatoren

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

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

Und |&in Bash.

A !ist kein Steueroperator, sondern ein reserviertes Wort . Es wird zu einem logischen NOT [Negationsoperator] in arithmetischen Ausdrücken und in Testkonstrukten (wobei immer noch ein Leerzeichen erforderlich ist).

A.1 Terminatoren auflisten

  • ; : Führt einen Befehl nach dem anderen aus, unabhängig vom Ergebnis des ersten.

    command1 ; command2

    Zuerst command1wird ausgeführt, im Vordergrund, und wenn es fertig ist, command2wird ausgeführt.

    Ein Zeilenumbruch, der sich nicht in einem Zeichenfolgenliteral oder nach bestimmten Schlüsselwörtern befindet , entspricht nicht dem Semikolonoperator. Eine Liste mit ;begrenzten einfachen Befehlen ist weiterhin eine Liste, da der Parser der Shell weiterhin die einfachen Befehle einlesen muss, die auf einen ;begrenzten einfachen Befehl folgen, bevor er ausgeführt wird, während eine neue Zeile eine gesamte Befehlsliste oder eine Liste von Listen begrenzen kann. Der Unterschied ist subtil, aber kompliziert: Da die Shell kein vorheriges Erfordernis zum Einlesen von Daten nach einer neuen Zeile hat, markiert die neue Zeile einen Punkt, an dem die Shell beginnen kann, die bereits eingelesenen einfachen Befehle auszuwerten, während dies ein ;Semikolon tut nicht.

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

     command1 & command2

    Hier command1wird im Hintergrund gestartet und command2beginnt sofort im Vordergrund zu laufen, ohne auf command1das Beenden zu warten .

    Ein Zeilenumbruch nach command1ist optional.

A.2 Logische Operatoren

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

     command1 && command2

    Hier command2wird ausgeführt, nachdem command1beendet wurde und nur wenn command1erfolgreich war (wenn sein 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; fiwenn der Rückgabestatus ignoriert wird.

  • || : Wird zum Erstellen von OR-Listen verwendet und ermöglicht es Ihnen, einen Befehl nur dann auszuführen, wenn ein anderer Befehl nicht erfolgreich beendet wurde.

     command1 || command2

    Hier command2wird nur ausgeführt, wenn dies command1fehlgeschlagen ist (wenn ein anderer Beendigungsstatus 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 auf kürzere Weise if ! command1; then command2; fi.

    Beachten Sie, dass &&und linksassoziativ ||sind; siehe Rangfolge der logischen Shell-Operatoren &&, || für mehr Informationen.

  • !: Dies ist ein reserviertes Wort, das als "nicht" -Operator fungiert (aber ein Trennzeichen haben muss) und verwendet wird, um den Rückgabestatus eines Befehls zu negieren - 0 zurückgeben, wenn der Befehl einen Nicht-Null-Status zurückgibt, 1 zurückgeben, wenn er den Status 0 zurückgibt Auch ein logisches NICHT für das testDienstprogramm.

    ! 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 wird als Pipeline bezeichnet .

     command1 | command2

    Jede Ausgabe, die von gedruckt wird, command1wird als Eingabe an übergeben command2.

  • |&: 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 nur verwendet, um das Ende einer case-Anweisung zu markieren . Ksh, bash und zsh unterstützen auch das Durchfallen ;&auf den nächsten Fall und ;;&(nicht in ATT ksh) das Fortfahren und Testen nachfolgender Fälle.

(und )werden verwendet, um Befehle zu gruppieren und in einer Subshell zu starten. {und }auch Gruppenbefehle, aber starten Sie sie nicht in einer Subshell. In dieser Antwort finden Sie eine Erläuterung der verschiedenen Arten von Klammern, Klammern und Klammern in der Shell-Syntax.

B. Umleitungsoperatoren

Umleitungsoperator

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

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

Mit diesen können Sie die Eingabe und Ausgabe Ihrer Befehle steuern. Sie können überall in einem einfachen Befehl erscheinen oder einem Befehl folgen. Weiterleitungen werden in der angegebenen Reihenfolge von links nach rechts verarbeitet.

  • < : Gibt einen Befehl ein.

    command < file.txt

    Das obige wird commandfür den Inhalt von ausgeführt file.txt.

  • <>: Wie oben, aber die Datei in offene Lese + Schreibmodus statt read-only :

    command <> file.txt

    Wenn die Datei nicht existiert, wird sie erstellt.

    Dieser Operator wird selten verwendet, da Befehle in der Regel nur von ihrer Standardeingabe gelesen werden , obwohl dies in bestimmten Situationen nützlich sein kann .

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

    command > out.txt

    Das Obige speichert die Ausgabe von commandals 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 >wird die Standardausgabe und der 2>Standardfehler umgeleitet. Die Ausgabe kann auch mit umgeleitet werden 1>. Da dies jedoch die Standardeinstellung ist, wird das 1normalerweise weggelassen und es wird einfach als geschrieben >.

    Also, läuft commandauf file.txtund speichert seinen Ausgang in out.txtund Fehlermeldungen in error.txtSie laufen würden:

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

    command >| out.txt

    Falls out.txtvorhanden, ersetzt die Ausgabe von commandihren Inhalt. Wenn es nicht existiert, wird es erstellt.

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

    command >> out.txt

    Wenn out.txtvorhanden, wird die Ausgabe von commandnach dem, was bereits enthalten ist , an die Ausgabe von angehängt. Wenn es nicht existiert, wird es erstellt.

  • &>, >&, >>&Und &>>: (Nicht - Standard). Leiten Sie sowohl Standardfehler als auch Standardausgabe um und ersetzen bzw. fügen Sie sie hinzu.

    command &> out.txt

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

    command &>> out.txt

    Wie oben, außer dass, wenn out.txtvorhanden, die Ausgabe und der Fehler von commanddaran angehängt werden.

    Die &>Variante stammt von bash, während die >&Variante von csh stammt (Jahrzehnte zuvor). Sie stehen in Konflikt mit anderen POSIX-Shell-Operatoren und sollten nicht in portierbaren shSkripten verwendet werden.

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

     command << WORD
         Text
     WORD

    Hier commandwird alles genommen, bis es das nächste Vorkommen von WORD( Textim obigen Beispiel) als Eingabe findet. Während WORDes oft ist EoFoder Variationen davon, kann es eine beliebige alphanumerische (und nicht nur) Zeichenfolge sein, die Sie mögen. Wenn WORDin Anführungszeichen gesetzt, wird der Text in diesem Dokument wörtlich behandelt und es werden keine Erweiterungen durchgeführt (z. B. für Variablen). Wenn es nicht in Anführungszeichen gesetzt ist, werden die Variablen erweitert. Weitere Einzelheiten finden Sie im Handbuch zur Bash .

    Wenn Sie die Ausgabe von command << WORD ... WORDdirekt in einen oder mehrere andere Befehle leiten möchten , müssen Sie die Pipe in dieselbe Zeile wie setzen << WORD. Sie können sie nicht nach dem abschließenden Wort oder in die folgende Zeile setzen. Zum Beispiel:

     command << WORD | command2 | command3...
         Text
     WORD
  • <<<: Hier Zeichenfolgen, ähnlich wie hier Dokumente, aber für eine einzelne Zeile vorgesehen. Diese existieren nur in der Unix-Portierung oder in rc (woher sie stammt), zsh, einigen Implementierungen von ksh, yash und bash.

    command <<< WORD

    Was auch immer angegeben wird, WORDwird erweitert und sein Wert wird als Eingabe an übergeben command. 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>&y x<&y) können zum Schließen oder Duplizieren von Dateideskriptoren verwendet werden. Einzelheiten dazu finden Sie im entsprechenden Abschnitt Ihres Shell-Handbuchs ( hier zum Beispiel für Bash).

Dies gilt nur für die gängigsten Operatoren von Bourne-ähnlichen Shells. Einige Shells verfügen über eigene zusätzliche Umleitungsoperatoren.

KSH, bash und zsh auch Konstrukte haben <(…), >(…)und =(…)(das letztere in zshonly). Dies sind keine Weiterleitungen, sondern Prozessersetzungen .

terdon
quelle
2
Es wäre wahrscheinlich erwähnenswert, dass nicht alle Shells gleich sind, und insbesondere die bashspezifischen Merkmale hervorzuheben.
Greg Hewgill
1
@ GregHewgill ja, ich habe es mit den Worten, dass ich in Bezug auf diskutieren wieso bash. Dies wird als kanonisches Q & A vorbereitet, um die verschiedenen "Was macht dieses seltsame Ding?" - Fragen zu schließen, und die meisten von ihnen stammen von Benutzern von Bash. Ich hoffe, dass sich jemand anderes einschaltet und für Nicht-Bash-Shells antwortet, aber das Hervorheben der Bash-spezifischen Shells macht sehr viel Sinn. Ich muss allerdings nachsehen, ich weiß nicht, welche von ihnen auf meinem Kopf sind.
Terdon
&>, >>>Und <<<sind alle nicht-Posix als der Verweis auf ist nicht nur für Nicht-alphanum chars in einem hier doc Namen. In dieser Antwort wird auch nur sehr wenig darüber gesprochen, wie sie funktionieren. Beispielsweise ist es fast sinnlos, über einen einfachen Befehl und einen Befehl zu sprechen, ohne zu erklären, was diese sind und wie die Shell entscheidet.
mikeserv
@mikeserv danke. Sie arbeiten jedoch an Bash und Zsh. Ich weiß nicht, was in dieser Liste wirklich bashspezifisch ist. Ich sollte das durchgehen und die Muscheln hinzufügen, in denen jeder arbeitet, aber dazu müsste man es zuerst herausfinden.
Terdon
1
@ Arc676 Nein, sie bewerten nicht als wahr oder falsch, das ist ein völlig anderer Kontext. Dies bedeutet nur, dass ein Exit-Wert ungleich 0 ein Problem anzeigt (nicht false) und ein Exit-Code von 0 einen Erfolg anzeigt (nicht true). Das war schon immer so und ist durchaus Standard. Ein Exit-Code ungleich 0 zeigt in jeder mir bekannten Umgebung einen Fehler an.
Terdon
60

Warnung bezüglich '>'

Unix-Anfänger, die gerade etwas über die E / A-Umleitung gelernt haben ( <und >), probieren oft Dinge wie

befehleingabedatei > die_gleiche_datei

oder

befehle … < file      > the_same_file

oder fast gleichwertig

cat Datei | befehl ...> die_gleiche_datei

( grep, sed, cut, sort, Und spellsind Beispiele für Befehle , die Menschen versucht sind , in Konstrukte wie diese zu verwenden.) Die Benutzer sind überrascht zu entdecken , dass diese Szenarien in der Datei führen immer leer.

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

Bevor ein Befehl ausgeführt wird, können seine Eingabe und Ausgabe unter Verwendung einer speziellen Notation umgeleitet werden, die von der Shell interpretiert wird.

Die ersten fünf Wörter sollten fett, kursiv, unterstrichen, vergrößert, blinkend, rot gefärbt und mit einem Ausrufezeichen im roten DreieckSymbol gekennzeichnet sein, um die Tatsache hervorzuheben, dass die Shell die angeforderten Umleitungen ausführt, bevor der Befehl ausgeführt wird . Und erinnere dich auch

Die Umleitung der Ausgabe bewirkt, dass die Datei zum Schreiben geöffnet wird. Wenn die Datei nicht existiert, wird sie erstellt. Wenn es existiert, wird es auf die Größe Null gekürzt.

  1. Also, in diesem Beispiel:

    sort roster > roster

    Die Shell öffnet die rosterDatei zum Schreiben und schneidet sie ab (dh, sie verwirft ihren gesamten Inhalt), bevor das sortProgramm ausgeführt wird. Natürlich kann nichts unternommen werden, um die Daten wiederherzustellen.

  2. Man könnte das naiv erwarten

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

    könnte besser sein. Da die Shell Umleitungen von links nach rechts verarbeitet, wird sie poemzum Lesen geöffnet (für trdie Standardeingabe), bevor sie zum Schreiben geöffnet wird (für die Standardausgabe). Aber es hilft nicht. Obwohl diese Abfolge von Vorgängen zwei Dateizugriffsnummern ergibt, verweisen beide auf dieselbe Datei. Wenn die Shell die Datei zum Lesen öffnet, ist der Inhalt immer noch vorhanden, aber sie werden immer noch blockiert, bevor das Programm ausgeführt wird. 

Also, was tun?

Die Lösungen umfassen:

  • Überprüfen Sie, ob das von Ihnen ausgeführte Programm über eine eigene interne Funktion verfügt, mit der Sie angeben können, wohin die Ausgabe gehen soll. Dies wird oft durch ein -o(oder --output=) Token angezeigt . Speziell,

    sort roster -o roster

    entspricht in etwa

    sort roster > roster

    Im ersten Fall sortöffnet das Programm die Ausgabedatei. Und es ist klug genug, die Ausgabedatei erst zu öffnen, nachdem sie alle Eingabedateien gelesen hat.

    In ähnlicher Weise zumindest einige Versionen sedhaben eine -i(edit i n setzen) Option , die verwendet werden kann , die Ausgabe zurück an die Eingabedatei (wieder zu schreiben , nachdem alle Eingaben gelesen wurden). Editoren wie ed/ ex, emacs, picound vi/ vim erlauben dem Benutzer eine Textdatei zu bearbeiten und die bearbeiteten Text in der Originaldatei speichern. Beachten Sie, dass ed(mindestens) nicht interaktiv verwendet werden kann.

    • vihat eine verwandte Funktion. Wenn Sie tippen , wird der Inhalt des Bearbeitungspuffers ausgegeben, die Ausgabe gelesen und in den Puffer eingefügt (wobei der ursprüngliche Inhalt ersetzt wird).:%!commandEntercommand
  • Einfach aber effektiv:

    befehleingabedatei > temp_datei   && mv temp_datei  eingabedatei

    Dies hat den Nachteil, dass input_fileein Link (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 letztendlich weltweit lesbar ist, selbst wenn das Original dies input_filenicht wäre.

    Variationen:

    • commandinput_file > temp_file && cp temp_file input_file && rm temp_file
      das wird immer noch (potenziell) die temp_fileWelt lesbar verlassen. Noch besser:
    • cp input_file temp_file && commandtemp_file > input_file && rm temp_file
      Dadurch bleiben der Link-Status, der Eigentümer und der Modus (Schutz) der Datei erhalten, was möglicherweise das Doppelte der E / A-Kosten zur Folge hat. (Möglicherweise müssen Sie eine Option wie -aoder -pon verwenden cp , um die Attribute beizubehalten.)
    • commandinput_file > temp_file &&
      cp --attributes-only --preserve=all input_file temp_file &&
      mv temp_file input_file
      (Nur aus Gründen der Lesbarkeit in separate Zeilen unterteilt.) Dadurch wird der Modus der Datei (und, wenn Sie als Root angemeldet sind, als Eigentümer) beibehalten. separate Datei.
  • Dieser Blog ("In-Place" -Bearbeitung von Dateien) schlägt vor und erklärt

    {rm eingabedatei   &&   befehl ...> eingabedatei ; } < Eingabedatei

    Dies setzt voraus, dass die commandStandardeingabe verarbeitet werden 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:

    befehleingabedatei | sponge the_same_file

    Weitere Informationen finden Sie in dieser Antwort .

Folgendes hat mich völlig überrascht: syntaxerror says :

[ Die meisten dieser Lösungen] werden auf einem schreibgeschützten Dateisystem versagen, wo „read-only“ bedeutet , dass Sie $HOME wird beschreibbar sein, sondern /tmpwerden nur gelesen werden (Standardeinstellung). Wenn Sie beispielsweise Ubuntu verwenden und die Wiederherstellungskonsole gestartet haben, ist dies normalerweise der Fall. Auch die hier-Dokument Betreiber <<<werden dort auch nicht funktionieren, da es erfordert /tmpwerden Lese- / Schreibzugriff , weil es eine temporäre Datei in auch dort schreiben.
(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 liefert, wie es Eingaben gibt (z. B. sortoder tr ohne die Option -doder -s), können Sie es versuchen
    befehleingabedatei | dd von = the_same_file conv = notrunc
    In dieser Antwort und dieser Antwort finden Sie weitere Informationen, einschließlich einer Erläuterung der obigen Punkte, sowie Alternativen, die funktionieren, wenn Ihr Befehl garantiert die gleiche Menge an Ausgabedaten liefert, wie es Eingaben oder weniger gibt (z. B. grepoder cut). Diese Antworten haben den Vorteil, dass sie keinen freien Speicherplatz benötigen (oder sehr wenig). Die obigen Antworten des Formulars setzen eindeutig voraus, dass genügend freier Speicherplatz für das System vorhanden ist, um die gesamte Eingabe- (alte) und Ausgabedatei (neue) gleichzeitig speichern zu können. Dies gilt natürlich auch für die meisten anderen Lösungen (z. B. und ). Ausnahme: Wird wahrscheinlich viel freien Speicherplatz benötigen, weilcommandinput_file > temp_file && …sed -ispongesort … | dd …sort muss alle Eingaben lesen, bevor Ausgaben geschrieben werden können, und es puffert wahrscheinlich die meisten, wenn nicht alle Daten in einer temporären Datei.
  • Nur für fortgeschrittene Benutzer:
    befehleingabedatei 1 <> die_selbe_datei
    kann gleichbedeutend mit der ddobigen Antwort sein. Die Syntax öffnet die angegebene Datei im Dateideskriptor sowohl für die Eingabe als auch für die Ausgabe , ohne sie abzuschneiden - eine Art Kombination aus und . Hinweis: Einige Programme (z. B. und ) lehnen die Ausführung in diesem Szenario möglicherweise ab, da sie erkennen können, dass die Eingabe und die Ausgabe dieselbe Datei sind. In dieser Antwort finden Sie eine Erläuterung der obigen Punkte und ein Skript, mit dem diese Antwort funktioniert, wenn Ihr Befehl garantiert die gleiche Menge an Ausgabedaten erzeugt, wie es Eingaben oder weniger gibt . Warnung: Ich habe Peters Skript nicht getestet und stehe daher nicht dafür ein.n<> filen n<n>catgrep

Also, was war die Frage?

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

… Und das zählt nicht Super User oder Ask Ubuntu. Ich habe viele Informationen aus den Antworten auf die obigen Fragen hier in diese Antwort aufgenommen, aber nicht alle. (Das heißt, für weitere Informationen lesen Sie die oben aufgeführten Fragen und deren Antworten.)

PS Ich habe keine Verbindung zu dem Blog, das ich oben zitiert habe.

Scott
quelle
Da diese Frage immer wieder auftaucht, dachte ich, ich würde versuchen, eine „kanonische Antwort“ zu schreiben. Soll ich es hier posten (und möglicherweise von einigen der anderen, am stärksten frequentierten Fragen darauf verlinken) oder zu einer der Fragen verschieben, die dieses Problem tatsächlich aufwerfen? Ist dies vielleicht auch eine Situation, in der Fragen zusammengeführt werden sollten?
Scott
/ tmp Ein Verzeichnis, das für Anwendungen verfügbar gemacht wird, die einen Speicherort zum Erstellen temporärer Dateien benötigen. Anwendungen dürfen Dateien in diesem Verzeichnis erstellen, jedoch nicht davon ausgehen, dass diese Dateien zwischen den Aufrufen der Anwendung aufbewahrt werden.
mikeserv
@mikeserv: Ja, (1) ich zitiere Syntaxfehler, und (2) ich sagte, ich war überrascht. Ich dachte, wenn irgendetwas Lese- und Schreibrechte hätte, wäre es das auch /tmp.
Scott
Nun, die Sache @syntaxerror sagte doppelt seltsam , weil, wie ich glaube, dashder Standard - Recovery - Shell auf Ubuntu wäre und es nicht nur versteht keinen <<<herestring, aber es wird auch anonyme Rohre für <<heredocuments und verwirrt nicht mit ${TMPDIR:-/tmp}für die Zweck überhaupt. Sehen Sie diese oder diese für Demos hier-Dokumenten - Handling. Auch warum die gleiche Menge an Ausgabe oder weniger Warnung?
mikeserv
@mikeserv: Nun, die dd … conv=notruncund die 1<>Antworten kürzen die Ausgabedatei niemals. Wenn also die Ausgabe des Befehls geringer ist als die Eingabe (z. B. grep), bleiben am Ende der Datei noch einige Bytes des Originals übrig. Und wenn der Ausgang des Eingang größer ist als ( zum Beispiel cat -n, nloder (potentiell) grep -n), gibt es ein Risiko , alte Daten überschreiben , bevor Sie es gelesen haben.
Scott
29

Weitere Beobachtungen auf ;, &, (und)

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

    command1 ;

    (mit nein command2). Dies ist äquivalent zu

    command1

    (Das heißt, es wird einfach command1im Vordergrund ausgeführt und wartet, bis es abgeschlossen ist.

    command1 &

    (ohne command2) wird command1im Hintergrund gestartet und gibt sofort eine weitere Shell-Eingabeaufforderung aus.

  • Im Gegensatz dazu command1 &&, command1 ||und command1 |macht keinen Sinn. Wenn Sie einen dieser Befehle eingeben, geht die Shell (wahrscheinlich) davon aus, dass der Befehl in einer anderen Zeile fortgesetzt wird. Es wird die zweite Shell-Eingabeaufforderung (Fortsetzung) angezeigt, die normalerweise auf eingestellt ist >, und der Lesevorgang wird fortgesetzt. In einem Shell-Skript wird nur die nächste Zeile gelesen und an das bereits Gelesene angehängt. (Achtung: Dies ist möglicherweise nicht das, was Sie möchten.)

    Hinweis: Einige Versionen einiger Shells können solche unvollständigen Befehle als Fehler behandeln. In solchen Fällen (oder in jedem Fall , in dem Sie einen langen Befehl haben) können Sie einen Backslash ( \) am Ende einer Zeile einfügen, um die Shell anzuweisen, den Befehl in einer anderen Zeile weiterzulesen:

    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, (und )kann zum Gruppieren von Befehlen verwendet werden. Die Aussage, dass sie für diese Diskussion „nicht wirklich relevant“ sind, ist umstritten. Einige der Befehle in terdon Antwort können Befehl seine Gruppen . Zum Beispiel,

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

    macht dies:

    • Laufen Sie command1und warten Sie, bis es fertig ist.
    • Führen Sie dann unabhängig vom Ergebnis der Ausführung dieses ersten Befehls den Befehl aus command2und warten Sie, bis er beendet ist.
    • Dann, wenn command2erfolgreich,

      • Laufen Sie command3und warten Sie, bis es fertig ist.
      • Führen Sie dann unabhängig vom Ergebnis der Ausführung dieses Befehls den Befehl aus command4und warten Sie, bis er beendet ist.

      Wenn dies command2fehlschlägt, beenden Sie die Verarbeitung der Befehlszeile.

  • Äußere Klammern, |bindet also sehr fest

    command1 | command2 || command3

    ist äquivalent zu

    ( command1 | command2 )  ||  command3

    und &&und ||binden , fester als ;, so

    command1 && command2 ; command3

    ist äquivalent zu

    ( command1 && command2 ) ;  command3

    dh command3wird unabhängig vom Exit-Status von command1und / oder ausgeführt command2.

G-Man
quelle
Perfekt, +1! Ich sagte, sie seien nicht relevant, weil ich nicht auf so viele Details eingehen wollte. Ich wollte eine Antwort, die als schnelles Cheatsheet für Neulinge dienen kann, die sich fragen, was all die seltsamen Kringel am Ende der verschiedenen Befehle sind. Ich wollte nicht implizieren, dass sie nicht nützlich sind. Vielen Dank, dass Sie all dies hinzugefügt haben.
Terdon
1
Ich mache mir Sorgen um das Problem der "kritischen Masse" - wenn wir alles veröffentlichen , was wir möglicherweise über Muscheln sagen könnten, erhalten wir unsere eigene TL; DR- Version des Bash-Referenzhandbuchs.
G-Man
Erwähnenswert ist auch: Anders als in Sprachen der C-Familie ist ;allein (oder ohne vorangestelltes Kommando) ein Syntaxfehler und keine leere Anweisung. Also ; ;ist ein Fehler. (Eine häufige Falle für neue Benutzer, IMHO). Also: ;;ist ein spezielles Trennzeichen für caseAnweisungen.
muru
1
@muru: Guter Punkt, aber lasst es uns verallgemeinern. Jede der Steuer Operatoren , die zwischen den Befehlen erscheinen: ;, &&, ||, &, und |, sind Fehler , wenn sie erscheinen mit nichts vorhergehenden ihnen. Auch Terdon sprach ;;(kurz) in seiner Antwort.
G-Man
1
@Wildcard: OK, ich sehe, woher du kommst. Das Schlüsselwort ist "Mai"; Ich habe nur gesagt, dass ich nicht garantieren kann, dass alle Shells solche Konstrukte (dh YMMV) akzeptieren. Offensichtlich habe ich das geschrieben, bevor ich über die Verwendung des linebreakTokens in der POSIX-Shell-Grammatik Bescheid wusste . Man kann also mit Sicherheit sagen, dass alle POSIX-kompatiblen Shells diese akzeptieren. Ich stehe zu meiner Erklärung als allgemeiner Haftungsausschluss; Wenn Sie eine ausreichend alte Pre-POSIX-Shell finden, z. B. eine aktuelle Bourne-Shell oder eine ältere, sind alle Wetten deaktiviert.
G-Man