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.
;
: Führt einen Befehl nach dem anderen aus, unabhängig vom Ergebnis des ersten.
command1 ; command2
Zuerst command1
wird ausgeführt, im Vordergrund, und wenn es fertig ist, command2
wird 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 command1
wird im Hintergrund gestartet und command2
beginnt sofort im Vordergrund zu laufen, ohne auf command1
das Beenden zu warten .
Ein Zeilenumbruch nach command1
ist optional.
&&
: Wird zum Erstellen von UND-Listen verwendet. Sie können einen Befehl nur ausführen, wenn ein anderer erfolgreich beendet wurde.
command1 && command2
Hier command2
wird ausgeführt, nachdem command1
beendet wurde und nur wenn command1
erfolgreich 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; fi
wenn 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 command2
wird nur ausgeführt, wenn dies command1
fehlgeschlagen 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 test
Dienstprogramm.
! command1
[ ! a = a ]
Und ein echter NOT-Operator in Arithmetic Expressions:
$ echo $((!0)) $((!23))
1 0
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 command
fü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 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 >
wird die Standardausgabe und der 2>
Standardfehler umgeleitet. Die Ausgabe kann auch mit umgeleitet werden 1>
. Da dies jedoch die Standardeinstellung ist, wird das 1
normalerweise weggelassen und es wird einfach als geschrieben >
.
Also, läuft command
auf file.txt
und speichert seinen Ausgang in out.txt
und Fehlermeldungen in error.txt
Sie 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 -C
oder set -o noclobber
) verweigert wird .
command >| out.txt
Falls out.txt
vorhanden, ersetzt die Ausgabe von command
ihren 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.txt
vorhanden, wird die Ausgabe von command
nach 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 command
werden 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.txt
vorhanden, die Ausgabe und der Fehler von command
daran 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 sh
Skripten verwendet werden.
<<
: Ein hier Dokument. Es wird häufig zum Drucken mehrzeiliger Zeichenfolgen verwendet.
command << WORD
Text
WORD
Hier command
wird alles genommen, bis es das nächste Vorkommen von WORD
( Text
im obigen Beispiel) als Eingabe findet. Während WORD
es oft ist EoF
oder Variationen davon, kann es eine beliebige alphanumerische (und nicht nur) Zeichenfolge sein, die Sie mögen. Wenn WORD
in 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 ... WORD
direkt 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, WORD
wird 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
Dies gilt nur für die gängigsten Operatoren von Bourne-ähnlichen Shells. Einige Shells verfügen über eigene zusätzliche Umleitungsoperatoren.
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.&>
,>>>
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.false
) und ein Exit-Code von 0 einen Erfolg anzeigt (nichttrue
). Das war schon immer so und ist durchaus Standard. Ein Exit-Code ungleich 0 zeigt in jeder mir bekannten Umgebung einen Fehler an.Warnung bezüglich '>'
Unix-Anfänger, die gerade etwas über die E / A-Umleitung gelernt haben (
<
und>
), probieren oft Dinge wieoder
oder fast gleichwertig
(
grep
,sed
,cut
,sort
, Undspell
sind 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) :
Die ersten fünf Wörter sollten fett, kursiv, unterstrichen, vergrößert, blinkend, rot gefärbt und mit einem Symbol gekennzeichnet sein, um die Tatsache hervorzuheben, dass die Shell die angeforderten Umleitungen ausführt, bevor der Befehl ausgeführt wird . Und erinnere dich auch
Also, in diesem Beispiel:
Die Shell öffnet die
roster
Datei zum Schreiben und schneidet sie ab (dh, sie verwirft ihren gesamten Inhalt), bevor dassort
Programm ausgeführt wird. Natürlich kann nichts unternommen werden, um die Daten wiederherzustellen.Man könnte das naiv erwarten
könnte besser sein. Da die Shell Umleitungen von links nach rechts verarbeitet, wird sie
poem
zum Lesen geöffnet (fürtr
die 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,entspricht in etwa
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
sed
haben 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 wieed
/ex
,emacs
,pico
undvi
/vim
erlauben dem Benutzer eine Textdatei zu bearbeiten und die bearbeiteten Text in der Originaldatei speichern. Beachten Sie, dassed
(mindestens) nicht interaktiv verwendet werden kann.vi
hat 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).:%!command
Entercommand
Einfach aber effektiv:
Dies hat den Nachteil, dass
input_file
ein 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 diesinput_file
nicht wäre.Variationen:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
das wird immer noch (potenziell) die
temp_file
Welt lesbar verlassen. Noch besser:cp input_file temp_file && command … temp_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
-a
oder-p
on verwendencp
, um die Attribute beizubehalten.)command … input_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
Dies setzt voraus, dass die
command
Standardeingabe 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
:Weitere Informationen finden Sie in dieser Antwort .
Folgendes hat mich völlig überrascht: syntaxerror says :
In diesem Fall kann Folgendes funktionieren:
sort
odertr
ohne die Option-d
oder-s
), können Sie es versuchen 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.grep
odercut
). 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, weilcommand … input_file > temp_file && …
sed -i
sponge
sort … | 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.dd
obigen 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<> file
n
n<
n>
cat
grep
Also, was war die Frage?
Dies war ein beliebtes Thema in U & L; es wird in den folgenden Fragen angesprochen:
iconv
die Eingabedatei durch die konvertierte Ausgabe ersetzen lassen?shuf file > file
hinterlässt der Befehl eine leere Datei?sort
mir dieser Befehl eine leere Datei?tr
stdout in eine Datei… 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.
quelle
/tmp
.dash
der 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?dd … conv=notrunc
und die1<>
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 Beispielcat -n
,nl
oder (potentiell)grep -n
), gibt es ein Risiko , alte Daten überschreiben , bevor Sie es gelesen haben.Weitere Beobachtungen auf
;
,&
,(
und)
Beachten Sie, dass einige der Befehle in der Antwort von terdon möglicherweise null sind. Zum Beispiel kann man sagen
(mit nein
command2
). Dies ist äquivalent zu(Das heißt, es wird einfach
command1
im Vordergrund ausgeführt und wartet, bis es abgeschlossen ist.(ohne
command2
) wirdcommand1
im Hintergrund gestartet und gibt sofort eine weitere Shell-Eingabeaufforderung aus.Im Gegensatz dazu
command1 &&
,command1 ||
undcommand1 |
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:oder
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,macht dies:
command1
und warten Sie, bis es fertig ist.command2
und warten Sie, bis er beendet ist.Dann, wenn
command2
erfolgreich,command3
und warten Sie, bis es fertig ist.command4
und warten Sie, bis er beendet ist.Wenn dies
command2
fehlschlägt, beenden Sie die Verarbeitung der Befehlszeile.Äußere Klammern,
|
bindet also sehr festist äquivalent zu
und
&&
und||
binden , fester als;
, soist äquivalent zu
dh
command3
wird unabhängig vom Exit-Status voncommand1
und / oder ausgeführtcommand2
.quelle
;
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ürcase
Anweisungen.;
,&&
,||
,&
, und|
, sind Fehler , wenn sie erscheinen mit nichts vorhergehenden ihnen. Auch Terdon sprach;;
(kurz) in seiner Antwort.linebreak
Tokens 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.