GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Verwirrt über stdin, stdout und stderr?

Es wäre richtiger zu sagen, dass stdin , stdout , und stderr sind eher "E/A-Streams" als Dateien. Wie Sie bemerkt haben, befinden sich diese Entitäten nicht im Dateisystem. Aber die Unix-Philosophie, soweit es I/O betrifft, ist "alles ist eine Datei". In der Praxis bedeutet das wirklich, dass Sie die gleichen Bibliotheksfunktionen und Schnittstellen verwenden können (printf ,scanf , read , write , select usw.), ohne sich Gedanken darüber machen zu müssen, ob der I/O-Stream mit einer Tastatur, einer Plattendatei, einem Socket, einer Pipe oder einer anderen I/O-Abstraktion verbunden ist.

Die meisten Programme müssen Eingaben lesen, Ausgaben schreiben und Fehler protokollieren, also stdin , stdout , und stderr sind für Sie als Programmierkomfort vordefiniert. Dies ist nur eine Konvention und wird vom Betriebssystem nicht erzwungen.


Ich fürchte, Ihr Verständnis ist völlig rückständig. :)

Denken Sie an "Standardeingang", "Standardausgang" und "Standardfehler" aus den Programmen Perspektive, nicht aus der Kernel-Perspektive.

Wenn ein Programm eine Ausgabe drucken muss, druckt es normalerweise auf "Standardausgabe". Ein Programm gibt die Ausgabe normalerweise mit printf auf die Standardausgabe aus , die NUR auf Standardausgabe druckt.

Wenn ein Programm Fehlerinformationen ausgeben muss (nicht unbedingt Ausnahmen, das sind Programmiersprachenkonstrukte, die auf einer viel höheren Ebene auferlegt werden), wird es normalerweise als "Standardfehler" ausgegeben. Dies geschieht normalerweise mit fprintf , die einen beim Drucken zu verwendenden Dateistream akzeptiert. Der Dateistrom kann jede zum Schreiben geöffnete Datei sein:Standardausgabe, Standardfehler oder jede andere Datei, die mit fopen geöffnet wurde oder fdopen .

„standard in“ wird verwendet, wenn die Datei Eingaben lesen muss, wobei fread verwendet wird oder fgets , oder getchar .

Jede dieser Dateien kann leicht umgeleitet werden aus der Shell wie folgt:

cat /etc/passwd > /tmp/out     # redirect cat's standard out to /tmp/foo
cat /nonexistant 2> /tmp/err   # redirect cat's standard error to /tmp/error
cat < /etc/passwd              # redirect cat's standard input to /etc/passwd

Oder die ganze Enchilada:

cat < /etc/passwd > /tmp/out 2> /tmp/err

Es gibt zwei wichtige Vorbehalte:Erstens sind „Standard In“, „Standard Out“ und „Standard Error“ nur eine Konvention. Sie sind sehr stark Konvention, aber es ist alles nur eine Vereinbarung, dass es sehr schön ist, Programme wie dieses ausführen zu können:grep echo /etc/services | awk '{print $2;}' | sort und lassen Sie die Standardausgaben jedes Programms in die Standardeingabe des nächsten Programms in der Pipeline einhängen.

Zweitens habe ich die Standard-ISO-C-Funktionen für die Arbeit mit Dateistreams (FILE * Objekte) -- auf Kernel-Ebene sind es alle Dateideskriptoren (int Verweise auf die Dateitabelle) und Operationen auf viel niedrigerer Ebene wie read und write , die nicht das fröhliche Puffern der ISO C-Funktionen ausführen. Ich dachte, es einfach zu halten und die einfacheren Funktionen zu verwenden, aber ich dachte trotzdem, dass Sie die Alternativen kennen sollten. :)


Standardeingabe - das ist das Dateihandle die Ihr Prozess liest, um Informationen von Ihnen zu erhalten.

Standardausgabe - Ihr Prozess schreibt herkömmliche Ausgaben in dieses Dateihandle.

Standardfehler - Ihr Prozess schreibt Diagnoseausgaben in dieses Dateihandle.

Das ist ungefähr so ​​dumm, wie ich es machen kann :-)

Natürlich ist das meistens Konvention. Nichts hindert Sie daran, Ihre Diagnoseinformationen auf Wunsch in die Standardausgabe zu schreiben. Sie können sogar die drei Dateihandles vollständig schließen und Ihre eigenen Dateien für I/O öffnen.

Wenn Ihr Prozess startet, sollten diese Handles bereits geöffnet sein und er kann nur von ihnen lesen und/oder darauf schreiben.

Standardmäßig sind sie wahrscheinlich mit Ihrem Endgerät verbunden (z. B. /dev/tty ), aber Shells erlauben es Ihnen, Verbindungen zwischen diesen Handles und bestimmten Dateien und/oder Geräten (oder sogar Pipelines zu anderen Prozessen) herzustellen, bevor Ihr Prozess startet (einige der möglichen Manipulationen sind ziemlich clever).

Ein Beispiel ist:

my_prog <inputfile 2>errorfile | grep XYZ

was wird:

  • erstellen Sie einen Prozess für my_prog .
  • öffne inputfile als Ihre Standardeingabe (Dateihandle 0).
  • öffne errorfile als Standardfehler (Dateihandle 2).
  • erstelle einen weiteren Prozess für grep .
  • hängen Sie die Standardausgabe von my_prog an in die Standardeingabe von grep .

Zu Ihrem Kommentar:

Wenn ich diese Dateien im Ordner /dev öffne, wie kommt es, dass ich nie die Ausgabe eines laufenden Prozesses sehe?

Das liegt daran, dass es sich nicht um normale Dateien handelt. Während UNIX alles darstellt als Datei in einem Dateisystem irgendwo, das macht es auf den untersten Ebenen nicht so. Die meisten Dateien im /dev Hierarchie sind entweder Zeichen- oder Blockgeräte, effektiv ein Gerätetreiber. Sie haben keine Größe, aber eine Haupt- und Nebengerätenummer.

Wenn Sie sie öffnen, sind Sie eher mit dem Gerätetreiber als mit einer physischen Datei verbunden, und der Gerätetreiber ist intelligent genug, um zu wissen, dass separate Prozesse separat behandelt werden sollten.

Dasselbe gilt für Linux /proc Dateisystem. Das sind keine echten Dateien, nur streng kontrollierte Gateways zu Kernel-Informationen.


Als Ergänzung zu den obigen Antworten finden Sie hier eine Zusammenfassung der Umleitungen:

EDIT:Diese Grafik ist nicht ganz korrekt.

Das erste Beispiel verwendet stdin überhaupt nicht, es übergibt "hello" als Argument an den echo-Befehl.

Die Grafik sagt auch, dass 2>&1 die gleiche Wirkung hat wie &> jedoch

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>

Dies liegt daran, dass &> eine Datei zum Umleiten benötigt und 2>&1 einfach stderr an stdout sendet


Linux
  1. Was ist mit der Verbindung von Stdout und Stdin gemeint?

  2. Möglichkeit, die Ausgabe eines Programms umzuleiten und trotzdem nach Stdout zu gehen?

  3. Warum stimmen Ls und Hexdump nicht über die Dateigröße überein?

  4. So leiten Sie die Ausgabe in eine Datei und stdout um

  5. Wie leite ich stderr und stdout in verschiedene Dateien in derselben Zeile im Skript um?

So leiten Sie stderr in Bash auf stdout um

Nur Stderr auf dem Bildschirm anzeigen, aber sowohl Stdout als auch Stderr in Datei schreiben?

Leiten Sie die gesamte Ausgabe in eine Datei in Bash um

Echo sowohl an stdout als auch an stderr

Ist es sicher, die Pufferung mit stdout und stderr zu deaktivieren?

echo oder print /dev/stdin /dev/stdout /dev/stderr