Bash
Umleitung
Suche…
Syntax
- Befehl </ Pfad / zu / Datei # Standardeingabe in Datei umleiten
- Befehl> / Pfad / zu / Datei # Standardausgabe in flie umleiten
- Befehl file_descriptor> / path / to / file # Ausgabe von file_descriptor in Datei umleiten
- Befehl> & file_descriptor # Ausgabe an file_descriptor umleiten
- Befehl file_descriptor> & another_file_descriptor # Umleitung file_descriptor auf another_file_descriptor
- Befehl <& file_descriptor # Leiten Sie file_descriptor zur Standardeingabe um
- Befehl &> / Pfad / zu / Datei # Standardausgabe und Standardfehler in Datei umleiten
Parameter
Parameter | Einzelheiten |
---|---|
interne Dateideskriptor | Eine ganze Zahl |
Richtung | Einer von > , < oder <> |
Externer Dateideskriptor oder -pfad | & gefolgt von einer Ganzzahl für den Dateideskriptor oder einem Pfad. |
Bemerkungen
UNIX-Konsolenprogramme verfügen über eine Eingabedatei und zwei Ausgabedateien (Eingabe- und Ausgabeströme sowie Geräte werden vom Betriebssystem als Dateien behandelt.) Dies sind in der Regel die Tastatur bzw. der Bildschirm, aber alle können umgeleitet werden um von einer Datei oder einem anderen Programm zu kommen oder zu gehen.
STDIN
ist eine Standardeingabe und empfängt die interaktiven Eingaben des Programms. STDIN
wird normalerweise der Dateideskriptor 0 zugewiesen.
STDOUT
ist Standardausgabe. Was auf STDOUT
wird als "Ergebnis" des Programms betrachtet. STDOUT
wird normalerweise der Dateideskriptor 1 zugewiesen.
STDERR
Fehlermeldungen angezeigt. Wenn ein Programm von der Konsole aus ausgeführt wird, wird STDERR
STDOUT
auf dem Bildschirm ausgegeben und kann nicht von STDOUT
. STDERR
wird normalerweise der Dateideskriptor 2 zugewiesen.
Die Reihenfolge der Weiterleitung ist wichtig
command > file 2>&1
STDOUT
beide ( STDOUT
und STDERR
) zur Datei um.
command 2>&1 > file
Umleitungen nur STDOUT
, weil der Dateideskriptor 2 in die Datei umgeleitet wird , auf den Dateideskriptor 1 (die nicht die Datei file
noch , wenn die Anweisung ausgewertet wird).
Jeder Befehl in einer Pipeline hat ein eigenes STDERR
(und STDOUT
), da es sich bei jedem STDOUT
um einen neuen Prozess handelt. Dies kann zu überraschenden Ergebnissen führen, wenn Sie davon ausgehen, dass eine Umleitung die gesamte Pipeline beeinflusst. Zum Beispiel dieser Befehl (zur besseren Lesbarkeit umschlossen):
$ python -c 'import sys;print >> sys.stderr, "Python error!"' \
| cut -f1 2>> error.log
druckt "Python-Fehler!" zur Konsole und nicht zur Protokolldatei. Hängen Sie den Fehler stattdessen an den Befehl, den Sie erfassen möchten:
$ python -c 'import sys;print >> sys.stderr, "Python error!"' 2>> error.log \
| cut -f1
Standardausgabe umleiten
>
Umleitung der Standardausgabe (auch bekannt als STDOUT
) des aktuellen Befehls in eine Datei oder einen anderen Deskriptor.
Diese Beispiele schreiben die Ausgabe des ls
in die Datei file.txt
ls >file.txt
> file.txt ls
Die Zieldatei wird erstellt, wenn sie nicht vorhanden ist. Andernfalls wird diese Datei abgeschnitten.
Der Standardumleitungsdeskriptor ist die Standardausgabe oder 1
wenn keine angegeben ist. Dieser Befehl entspricht den vorherigen Beispielen, wobei die Standardausgabe explizit angegeben ist:
ls 1>file.txt
Hinweis: Die Umleitung wird von der ausgeführten Shell und nicht vom ausgeführten Befehl initialisiert, daher erfolgt sie vor der Befehlsausführung.
STDIN umleiten
<
liest aus seinem rechten Argument und schreibt zu seinem linken Argument.
Um eine Datei in STDIN
zu schreiben, sollten Sie /tmp/a_file
lesen und in STDIN
schreiben, dh 0</tmp/a_file
Hinweis: Der interne Dateideskriptor ist standardmäßig auf 0
( STDIN
) für <
$ echo "b" > /tmp/list.txt
$ echo "a" >> /tmp/list.txt
$ echo "c" >> /tmp/list.txt
$ sort < /tmp/list.txt
a
b
c
Umleiten von STDOUT und STDERR
Dateideskriptoren wie 0
und 1
sind Zeiger. Wir ändern, worauf Dateideskriptoren bei der Umleitung verweisen. >/dev/null
bedeutet 1
zeigt auf /dev/null
.
Zuerst zeigen wir 1
( STDOUT
) auf /dev/null
dann Punkt 2
( STDERR
) auf das, worauf 1
verweist.
# STDERR is redirect to STDOUT: redirected to /dev/null,
# effectually redirecting both STDERR and STDOUT to /dev/null
echo 'hello' > /dev/null 2>&1
Dies kann weiter verkürzt werden:
echo 'hello' &> /dev/null
Dieses Formular kann jedoch in der Produktion unerwünscht sein, wenn die Kompatibilität mit der Shell problematisch ist, da es mit POSIX kollidiert, Mehrdeutigkeiten beim Analysieren einführt und Shells ohne diese Funktion dies falsch interpretieren:
# Actual code
echo 'hello' &> /dev/null
echo 'hello' &> /dev/null 'goodbye'
# Desired behavior
echo 'hello' > /dev/null 2>&1
echo 'hello' 'goodbye' > /dev/null 2>&1
# Actual behavior
echo 'hello' &
echo 'hello' & goodbye > /dev/null
HINWEIS: Es ist bekannt, dass &>
in Bash und Zsh wie gewünscht funktioniert.
Umleitung von STDERR
2
ist STDERR
.
$ echo_to_stderr 2>/dev/null # echos nothing
Definitionen:
echo_to_stderr
ist ein Befehl, der "stderr"
in STDERR
schreibt
echo_to_stderr () {
echo stderr >&2
}
$ echo_to_stderr
stderr
Append vs Truncate
Abschneiden >
- Erstellen Sie die angegebene Datei, falls diese nicht vorhanden ist.
- Abschneiden (Dateiinhalt entfernen)
- In die Datei schreiben
$ echo "first line" > /tmp/lines
$ echo "second line" > /tmp/lines
$ cat /tmp/lines
second line
Anhängen >>
- Erstellen Sie die angegebene Datei, falls diese nicht vorhanden ist.
- Datei anhängen (Schreiben am Ende der Datei).
# Overwrite existing file
$ echo "first line" > /tmp/lines
# Append a second line
$ echo "second line" >> /tmp/lines
$ cat /tmp/lines
first line
second line
STDIN, STDOUT und STDERR erklärt
Befehle haben einen Eingang (STDIN) und zwei Arten von Ausgängen, Standardausgang (STDOUT) und Standardfehler (STDERR).
Zum Beispiel:
STDIN
root@server~# read
Type some text here
Die Standardeingabe dient zur Eingabe eines Programms. (Hier verwenden wir das read
Builtin , um eine Zeile aus STDIN zu lesen.)
STDOUT
root@server~# ls file
file
Die Standardausgabe wird im Allgemeinen für die "normale" Ausgabe eines Befehls verwendet. Zum Beispiel ls
listet die Dateien, so werden die Dateien an STDOUT gesendet.
STDERR
root@server~# ls anotherfile
ls: cannot access 'anotherfile': No such file or directory
Standardfehler werden (wie der Name schon sagt) für Fehlermeldungen verwendet. Da es sich bei dieser Nachricht nicht um eine Liste von Dateien handelt, wird sie an STDERR gesendet.
STDIN, STDOUT und STDERR sind die drei Standardströme. Sie sind in der Shell durch eine Nummer und nicht durch einen Namen gekennzeichnet:
0 = Standard in
1 = Standard aus
2 = Standardfehler
Standardmäßig ist STDIN an die Tastatur angeschlossen, und STDOUT und STDERR werden im Terminal angezeigt. Wir können jedoch entweder STDOUT oder STDERR an das weiterleiten, was wir brauchen. Nehmen wir zum Beispiel an, dass Sie nur den Standard out benötigen und alle Fehlermeldungen, die auf dem Standardfehler gedruckt werden, unterdrückt werden sollen. Dann verwenden wir die Deskriptoren 1
und 2
.
Umleitung von STDERR nach / dev / null
Nehmen wir das vorige Beispiel
root@server~# ls anotherfile 2>/dev/null
root@server~#
In diesem Fall wird ein STDERR an / dev / null weitergeleitet (eine spezielle Datei, die alle darin enthaltenen Einträge ignoriert), so dass keine Fehlerausgabe in der Shell erfolgt.
Umleiten mehrerer Befehle in dieselbe Datei
{
echo "contents of home directory"
ls ~
} > output.txt
Named Pipes verwenden
Manchmal möchten Sie möglicherweise etwas von einem Programm ausgeben und in ein anderes Programm eingeben, können jedoch keine Standardpipe verwenden.
ls -l | grep ".log"
Sie können einfach in eine temporäre Datei schreiben:
touch tempFile.txt
ls -l > tempFile.txt
grep ".log" < tempFile.txt
Für die meisten Anwendungen funktioniert das tempFile
Niemand weiß jedoch, was tempFile
tut, und jemand könnte es entfernen, wenn es die Ausgabe von ls -l
in diesem Verzeichnis enthält. Hier kommt eine Named Pipe ins Spiel:
mkfifo myPipe
ls -l > myPipe
grep ".log" < myPipe
myPipe
ist technisch gesehen eine Datei (alles ist in Linux), also ls -l
in einem leeren Verzeichnis, in dem wir gerade eine Pipe erstellt haben:
mkdir pipeFolder
cd pipeFolder
mkfifo myPipe
ls -l
Die Ausgabe ist:
prw-r--r-- 1 root root 0 Jul 25 11:20 myPipe
Beachten Sie das erste Zeichen in den Berechtigungen. Es wird als Pipe und nicht als Datei aufgeführt.
Jetzt lass uns etwas Cooles machen.
Öffnen Sie ein Terminal und notieren Sie sich das Verzeichnis (oder erstellen Sie eines, damit die Bereinigung einfach ist), und erstellen Sie eine Pipe.
mkfifo myPipe
Jetzt lass uns etwas in die Pfeife legen.
echo "Hello from the other side" > myPipe
Sie werden feststellen, dass dies hängt, die andere Seite der Leitung ist immer noch geschlossen. Lassen Sie uns die andere Seite der Pfeife öffnen und das Zeug durchlassen.
Öffnen Sie ein anderes Terminal und wechseln Sie in das Verzeichnis, in dem sich die Pipe befindet (oder wenn Sie es wissen, stellen Sie es der Pipe voran):
cat < myPipe
Sie werden feststellen, dass nach hello from the other side
Ausgabe hello from the other side
das Programm im ersten Terminal beendet wird, wie auch im zweiten Terminal.
Führen Sie nun die Befehle in umgekehrter Reihenfolge aus. Beginnen Sie mit cat < myPipe
und geben Sie etwas ein. Es funktioniert immer noch, weil ein Programm wartet, bis sich etwas in der Pipe befindet, bevor es beendet wird, weil es weiß, dass es etwas bekommen muss.
Named Pipes können nützlich sein, um Informationen zwischen Terminals oder zwischen Programmen zu verschieben.
Pfeifen sind klein. Sobald der Writer voll ist, blockiert der Writer, bis einige Leser den Inhalt lesen. Daher müssen Sie entweder den Reader und den Writer in verschiedenen Terminals oder das eine oder andere im Hintergrund ausführen:
ls -l /tmp > myPipe &
cat < myPipe
Weitere Beispiele mit Named Pipes:
Beispiel 1 - Alle Befehle auf demselben Terminal / derselben Shell
$ { ls -l && cat file3; } >mypipe & $ cat <mypipe # Output: Prints ls -l data and then prints file3 contents on screen
Beispiel 2 - Alle Befehle auf demselben Terminal / derselben Shell
$ ls -l >mypipe & $ cat file3 >mypipe & $ cat <mypipe #Output: This prints on screen the contents of mypipe.
file3
dass zuerst der Inhalt vonfile3
angezeigt wird und dann diels -l
Daten angezeigt werden (LIFO-Konfiguration).Beispiel 3 - Alle Befehle auf demselben Terminal / derselben Shell
$ { pipedata=$(<mypipe) && echo "$pipedata"; } & $ ls >mypipe # Output: Prints the output of ls directly on screen
$pipedata
dass die Variable$pipedata
nicht für die Verwendung in der Hauptterminal- / Main-Shell verfügbar ist, da die Verwendung von&
eine Subshell verwendet und$pipedata
nur in dieser Subshell verfügbar war.Beispiel 4 - Alle Befehle auf demselben Terminal / derselben Shell
$ export pipedata $ pipedata=$(<mypipe) & $ ls -l *.sh >mypipe $ echo "$pipedata" #Output : Prints correctly the contents of mypipe
Dadurch wird der Wert der
$pipedata
Variablen in der Haupt-Shell aufgrund der$pipedata
Variablen korrekt$pipedata
. Das Hauptterminal / die Haupt-Shell hängt nicht an dem Aufruf einer Hintergrund-Shell (&
).
Fehlermeldungen an stderr ausgeben
Fehlermeldungen werden im Allgemeinen zu Debugging-Zwecken oder zur Bereitstellung einer umfassenden Benutzererfahrung in ein Skript aufgenommen. Schreiben Sie einfach eine Fehlermeldung wie diese:
cmd || echo 'cmd failed'
kann für einfache Fälle funktionieren, aber es ist nicht der übliche Weg. In diesem Beispiel verschmutzt die Fehlermeldung die tatsächliche Ausgabe des Skripts, indem sowohl Fehler als auch erfolgreiche Ausgabe in stdout
gemischt werden.
Kurz gesagt, die Fehlermeldung sollte an stderr
stdout
. Es ist ziemlich einfach:
cmd || echo 'cmd failed' >/dev/stderr
Ein anderes Beispiel:
if cmd; then
echo 'success'
else
echo 'cmd failed' >/dev/stderr
fi
Im obigen Beispiel wird die Erfolgsmeldung auf stdout
gedruckt, während die Fehlermeldung auf stderr
gedruckt wird.
Eine bessere Möglichkeit, eine Fehlermeldung zu drucken, ist das Definieren einer Funktion:
err(){
echo "E: $*" >>/dev/stderr
}
Wenn Sie jetzt einen Fehler drucken müssen:
err "My error message"
Umleitung zu Netzwerkadressen
Bash behandelt einige Pfade als besonders und kann einige Netzwerkkommunikationen durch Schreiben in /dev/{udp|tcp}/host/port
. Bash kann keinen abhörenden Server einrichten, kann jedoch eine Verbindung initiieren, und für TCP können die Ergebnisse mindestens gelesen werden.
Um beispielsweise eine einfache Webanfrage zu senden, können Sie Folgendes tun:
exec 3</dev/tcp/www.google.com/80
printf 'GET / HTTP/1.0\r\n\r\n' >&3
cat <&3
Die Ergebnisse der Standardwebseite von www.google.com
werden in stdout
gedruckt.
Ähnlich
printf 'HI\n' >/dev/udp/192.168.1.1/6666
würde eine UDP-Nachricht mit HI\n
an einen Listener unter 192.168.1.1:6666
senden