webentwicklung-frage-antwort-db.com.de

Wie funktioniert cmd>/dev/null 2> & 1?

Ich lese gerade über das Umleiten von Daten zu /dev/null und habe deshalb einen einfachen Test versucht:

ping a.b.c  # which results in an address not found

Wenn ich das versuche:

ping a.b.c > /dev/null # prints the same error message as the one above

Wenn ich das mache:

ping a.b.c > /dev/null 2>&1 # The error message is gone

Diese letzte Lösung ist die gewünschte Lösung, aber was passiert mit diesem 2>&1? Meine bisherigen Untersuchungen legen nahe, dass 2 für stderr und 1 für stdout steht. Wenn ich es also so lese, sieht es so aus, als würde ich eine stderr-Datei erstellen und stdout dorthin umleiten?

Wenn dies der Fall ist, was bewirkt der & in diesem Befehl?

11
hax0r_n_code

Sie haben Recht, 2 ist STDERR, 1 ist STDOUT. Wenn Sie 2>&1 ausführen, sagen Sie: "In STDOUT (1) die Dinge drucken, die in STDERR (2) gehen würden". Und davor sagten Sie, Ihre STDOUT würde zu /dev/null gehen. Daher ist nichts zu sehen. In den Beispielen 1 und 2 wird die Ausgabemeldung angezeigt, da sie in STDERR gedruckt wird, da bei einer regulären Umleitung nur STDOUT umgeleitet wird.

Und wenn Sie die Umleitung durchführen, erstellen Sie keine STDERR, die Prozesse haben immer eine STDERR und eine STDOUT, wenn sie erstellt werden.

12
msb

Betrachten Sie den folgenden Code, der das Wort "stdout" zu stdout und das Wort "stderror" zu stderror druckt.

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

Beachten Sie, dass der Operator '&' bash mitteilt, dass 2 ein Dateideskriptor (der auf das stderr zeigt) und kein Dateiname ist. Wenn wir das '&' weglassen, gibt dieser Befehl stdout in stdout aus, erstellt eine Datei mit dem Namen "2" und schreibt dort stderror.

Wenn Sie mit dem obigen Code experimentieren, können Sie sich selbst davon überzeugen, wie Umleitungsoperatoren funktionieren. Wenn Sie zum Beispiel ändern, welche Datei von den beiden Deskriptoren 1, 2 zu /dev/null umgeleitet wird, löschen die folgenden beiden Codezeilen alles aus dem stdout und alles aus dem stderror (was übrig bleibt wird gedruckt).

$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout

Nun nähern wir uns dem Kern der Frage (ersetzen Sie Ihr Beispiel durch mein), warum

(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1

keine Ausgabe erzeugen? Um dies wirklich zu verstehen, empfehle ich Ihnen dringend, diese Webseite über Dateideskriptortabellen zu lesen. Angenommen, Sie haben diese Lektüre durchgeführt, können wir fortfahren. Beachten Sie, dass Bash von links nach rechts verarbeitet wird. Daher sieht Bash zuerst >/dev/null (das ist dasselbe wie 1>/dev/null) und setzt den Dateideskriptor 1 so, dass er auf/dev/null anstatt auf stdout zeigt. Danach bewegt sich Bash nach rechts und sieht 2>&1. Dies setzt den Dateideskriptor 2 um auf dieselbe Datei zu verweisen wie Dateideskriptor 1 (und nicht auf Dateideskriptor 1 selbst !!!!) (siehe diese Ressource zu Zeigern für weitere Informationen) Dateideskriptor 1 zeigt auf/dev/null, und Dateideskriptor 2 zeigt auf dieselbe Datei wie Dateideskriptor 1, Dateideskriptor 2 zeigt jetzt auch auf/dev/null warum wird keine Ausgabe gerendert.


Um zu testen, ob Sie das Konzept wirklich verstehen, versuchen Sie, die Ausgabe zu erraten, wenn wir die Umleitungsreihenfolge ändern:

(echo "stdout"; echo "stderror" >&2)  2>&1 >/dev/null

standardfehler

Der Grund hierfür ist, dass Bash bei der Auswertung von links nach rechts 2> & 1 sieht und daher den Dateideskriptor 2 so einstellt, dass er auf dieselbe Stelle verweist wie Dateideskriptor 1, dh stdout. Anschließend wird der Dateideskriptor 1 (denken Sie daran, dass>/dev/null = 1>/dev/null) so eingestellt, dass er auf>/dev/null zeigt, wodurch alles gelöscht wird, was normalerweise an den Standardausgang gesendet wird. Somit bleibt uns nur das übrig, was nicht in der Subshell an stdout gesendet wurde (der Code in Klammern) - d. H. "Stderror". Das Interessante daran ist, dass, obwohl 1 nur ein Zeiger auf die Standardausgabe ist, das Umleiten von Zeiger 2 auf 1 über 2>&1 KEINE Kette von Zeigern 2 -> 1 -> Standardausgabe bildet. Wenn dies der Fall wäre, würde der Code 2>&1 >/dev/null als Ergebnis der Umleitung von 1 nach/dev/null die Zeigerkette 2 -> 1 ->/dev/null ergeben, und somit würde der Code im Gegensatz zu dem, was wir oben gesehen haben, nichts erzeugen .


Abschließend möchte ich darauf hinweisen, dass es einen einfacheren Weg gibt, dies zu tun:

In Abschnitt 3.6.4 hier sehen wir, dass wir den Operator &> verwenden können, um sowohl stdout als auch stderr umzuleiten. Um also sowohl die Ausgabe von stderr als auch von stdout eines Befehls an \dev\null umzuleiten (wodurch die Ausgabe gelöscht wird), geben Sie einfach $ command &> /dev/null ein oder in meinem Beispiel:

$ (echo "stdout"; echo "stderror" >&2) &>/dev/null

Die zentralen Thesen:

  • Dateideskriptoren verhalten sich wie Zeiger (obwohl Dateideskriptoren nicht mit Dateizeigern identisch sind)
  • Das Umleiten eines Dateideskriptors "a" zu einem Dateideskriptor "b", der auf die Datei "f" zeigt, bewirkt, dass der Dateideskriptor "a" auf dieselbe Stelle verweist wie der Dateideskriptor b - die Datei "f". Es bildet KEINE Kette von Zeigern a -> b -> f
  • Aus diesem Grund ist die Reihenfolge wichtig, 2>&1 >/dev/null ist! = >/dev/null 2>&1. Einer erzeugt Output und der andere nicht!

Schauen Sie sich zum Schluss diese großartigen Ressourcen an:

Bash-Dokumentation zur Umleitung , Erläuterung der Dateideskriptortabellen , Einführung in Zeiger

0
Evan Rosica