Verwirrt über stdin, stdout und stderr?

229

Ich bin ziemlich verwirrt mit dem Zweck dieser drei Dateien. Wenn mein Verständnis richtig ist, stdinist die Datei, in die ein Programm in seine Anforderungen schreibt, um eine Aufgabe im Prozess auszuführen, stdoutdie Datei, in die der Kernel seine Ausgabe schreibt, und der Prozess, der ihn auffordert, auf die Informationen zuzugreifen, und stderrdie Datei, in die welche alle Ausnahmen eingegeben werden. Beim Öffnen dieser Dateien, um zu überprüfen, ob diese tatsächlich auftreten, habe ich nichts gefunden, was darauf hindeutet!

Was ich wissen möchte, ist, was genau der Zweck dieser Dateien ist, absolut heruntergekommene Antwort mit sehr wenig Fachjargon!

Shouvik
quelle
36
Beobachtung: Diese Frage war bereits 2010 akzeptabel, wurde aber heutzutage sehr schnell abgelehnt.
bis zum
3
@Brandon Kannst du einen Grund angeben? Ich denke, es wäre wertvoll für Ihren Kommentar.
Unabhängiger
3
@byxor um fair zu sein, werde ich fragen: Hat Op's Post nach Leuten gefragt, die ihm beim Debuggen seines Codes helfen sollen? es scheint, dass Shouvik eine Frage bezüglich des Zwecks von stdin, stdout und stderr gestellt hat. Der Posten der Operation scheint aus Neugier zu sein, nicht wahr? (Ich lerne tatsächlich selbst darüber atm. Danke, SO, dass
du
2
@ user123456 du bist richtig. Ich habe gelernt, Softwareentwickler zu werden, und S / O war damals ein großartiger Ort, um etwas über Programmierung zu lernen. Wir wollten ursprünglich, dass es eine Art Wiki-Dienst für alle Fragen der Informatik ist. #juniorDevForLife
Shouvik
3
@Shouvik danke für das bisschen Geschichte. Ich lerne auch, wie man ein Softwareentwickler ist (wurde gerade in ein cooles Camp in SF aufgenommen). Ich bin noch ziemlich neu in S / O und immer noch unsicher, was ich posten kann und was nicht. Ich finde, dass die Moderation hier ziemlich streng sein kann. Ich mag diesen Hashtag. #juniorDevForLife. Ich würde Sie kontaktieren, anstatt hier zu kommentieren, da dies nichts zur Diskussion beiträgt, aber ich glaube nicht, dass S / O ein PM-System hat. Ich wünsche ihnen einen wunderbaren Tag.
Sansae

Antworten:

251

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

Standardausgabe - Ihr Prozess schreibt normale Informationen in dieses Dateihandle.

Standardfehler - Ihr Prozess schreibt Fehlerinformationen in dieses Dateihandle.

Das ist ungefähr so ​​niedergeschlagen, wie ich es schaffen kann :-)

Das ist natürlich meistens konventionell. Nichts hindert Sie daran, Ihre Fehlerinformationen in die Standardausgabe zu schreiben, wenn Sie dies wünschen. Sie können die drei Dateihandles sogar vollständig schließen und Ihre eigenen Dateien für E / A ö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 mithilfe von Shells können Sie Verbindungen zwischen diesen Handles und bestimmten Dateien und / oder Geräten (oder sogar Pipelines zu anderen Prozessen) herstellen, bevor Ihr Prozess beginnt (einige davon) Die möglichen Manipulationen sind ziemlich klug.

Ein Beispiel ist:

my_prog <inputfile 2>errorfile | grep XYZ

welches wird:

  • Erstellen Sie einen Prozess für my_prog.
  • Öffnen Sie inputfileals Standardeingabe (Dateihandle 0).
  • Öffnen Sie errorfileals Standardfehler (Dateihandle 2).
  • Erstellen Sie einen anderen Prozess für grep.
  • Fügen Sie den Standardausgang von my_progdem Standardeingang von hinzu grep.

Zu Ihrem Kommentar:

Wie kommt es, dass ich beim Öffnen dieser Dateien im Ordner / dev nie die Ausgabe eines laufenden Prozesses sehe?

Es ist, weil sie keine normalen Dateien sind. Während UNIX alles irgendwo als Datei in einem Dateisystem darstellt, ist dies auf den niedrigsten Ebenen nicht der Fall. Die meisten Dateien in der /devHierarchie sind entweder Zeichen- oder Blockgeräte, praktisch ein Gerätetreiber. Sie haben keine Größe, aber eine Haupt- und eine 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.

Gleiches gilt für das Linux- /procDateisystem. Dies sind keine echten Dateien, sondern streng kontrollierte Gateways zu Kernelinformationen.

paxdiablo
quelle
1
Das ist für Ihre Antwort. Obwohl ich den Zweck der Dateien anhand Ihrer Beschreibung verstehen kann, möchte ich eine Ebene weiter verschieben. Wenn ich diese Dateien im Ordner / dev öffne, kann ich dann nie die Ausgabe eines laufenden Prozesses sehen. Angenommen, ich führe top auf dem Terminal aus. Soll es seine Ergebnisse nicht regelmäßig in die stdout-Datei ausgeben? Wenn es aktualisiert wird, sollte ich in der Lage sein, eine Instanz der Ausgabe zu sehen, die auf diese Datei gedruckt wird. Dies ist jedoch nicht der Fall. Diese Dateien sind also nicht dieselben (die im Verzeichnis / dev).
Shouvik
7
Weil das technisch gesehen keine Dateien sind. Sie sind Geräteknoten, die ein bestimmtes Gerät angeben, auf das geschrieben werden soll. UNIX kann präsentieren Ihnen alles als Datei Abstraktion aber das macht es nicht so auf den tiefsten Ebenen.
Paxdiablo
1
Verwenden Sie die Shell-Umleitungsfunktion. xyz >xyz.outschreibt Ihre Standardausgabe in eine physische Datei, die von anderen Prozessen gelesen werden kann. xyz | grep somethingverbindet xyzstdout grepdirekter mit stdin. Wenn Sie uneingeschränkten Zugriff auf einen Prozess wünschen, den Sie nicht auf diese Weise steuern, müssen Sie sich etwas ansehen /procoder Code schreiben, um die Ausgabe zu filtern, indem Sie sich irgendwie in den Kernel einhängen. Es mag andere Lösungen geben, aber sie sind wahrscheinlich alle so gefährlich wie die anderen :-)
paxdiablo
20
@Shouvik, beachten Sie, dass dies /dev/stdinein Symlink zu /proc/self/fd/0- dem ersten Dateideskriptor ist, den das aktuell ausgeführte Programm geöffnet hat. Was also darauf hinweist, /dev/stdinändert sich von Programm zu Programm, da /proc/self/immer auf das aktuell laufende Programm verwiesen wird . (Welches Programm auch immer den openAufruf ausführt .) /dev/stdinUnd Freunde wurden dorthin gebracht, um Setuid-Shell-Skripte sicherer zu machen und den Dateinamen /dev/stdinan Programme zu übergeben, die nur mit Dateien arbeiten, aber interaktiver steuern möchten. (Eines Tages wird dies ein nützlicher Trick für Sie sein. :)
Sarnold
1
@ CarlosW.Mercado, eine Datei ist eine physische Manifestation der Daten. Zum Beispiel die auf der Festplatte gespeicherten Bits. Ein Dateihandle ist (normalerweise) ein kleines Token, mit dem auf diese Datei verwiesen wird, sobald Sie sie geöffnet haben.
Paxdiablo
62

Es wäre richtiger zu sagen , dass stdin, stdoutund stderrist als Dateien eher „I / O - Streams“. Wie Sie bemerkt haben, befinden sich diese Entitäten nicht im Dateisystem. Die Unix-Philosophie in Bezug auf E / A lautet jedoch "Alles ist eine Datei". In der Praxis das wirklich bedeutet , dass Sie die gleichen Bibliotheksfunktionen und Schnittstellen verwenden können ( printf, scanf, read, write, select, etc.) , ohne sich Gedanken darüber , ob die I / O - Stream mit einer Tastatur verbunden ist, eine Plattendatei, eine Steckdose, ein Rohr, oder eine andere E / A-Abstraktion.

Die meisten Programme müssen Eingang, Schreibausgang lesen, und Protokollfehler, so stdin, stdoutund stderrsind für Sie vordefiniert, als Programmierkomfort. Dies ist nur eine Konvention und wird vom Betriebssystem nicht erzwungen.

Jim Lewis
quelle
Vielen Dank für Ihre Beiträge. Würdest du zufällig wissen, wie ich den Ausgabedatenstrom eines Prozesses abfangen und in eine eigene Datei ausgeben könnte?
Shouvik
51

Als Ergänzung zu den obigen Antworten finden Sie hier eine Zusammenfassung der Weiterleitungen: Weiterleitungs-Cheatsheet

EDIT: Diese Grafik ist nicht ganz korrekt, aber ich bin nicht sicher, warum ...

Die Grafik sagt 2> & 1 hat jedoch den gleichen Effekt wie &>

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>
Leopold Gault
quelle
4
Ihr Kommentar in Kombination mit der akzeptierten Antwort ist absolut sinnvoll und erklärt die Dinge klar! Vielen Dank!
Mykola
1
Ein Bild sagt mehr als tausend Worte !
tauseef_CuriousGuy
22

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

Denken Sie aus der Sicht des Programms an "Standard In", "Standard Out" und "Standard Error" , nicht aus Sicht des Kernels.

Wenn ein Programm eine Ausgabe drucken muss, druckt es normalerweise nach "Standardausgang". Ein Programm druckt normalerweise die Ausgabe nach Standardausgabe mit printf, wobei NUR nach Standardausgabe gedruckt wird.

Wenn ein Programm Fehlerinformationen drucken muss (nicht unbedingt Ausnahmen, dies ist ein Programmiersprachenkonstrukt, das auf einer viel höheren Ebene auferlegt wird), wird es normalerweise als "Standardfehler" gedruckt. Dies geschieht normalerweise mit fprintf, wodurch ein Dateistream akzeptiert wird, der beim Drucken verwendet wird. Der Dateistream kann eine beliebige Datei sein, die zum Schreiben geöffnet wurde: Standardausgabe, Standardfehler oder eine andere Datei, die mit fopenoder geöffnet wurde fdopen.

"Standard in" wird verwendet, wenn die Datei Eingaben mit freadoder fgetsoder lesen muss getchar.

Jede dieser Dateien kann wie folgt einfach von der Shell umgeleitet werden :

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 Einschränkungen: Erstens sind "Standard in", "Standard out" und "Standardfehler" nur eine Konvention. Sie sind eine sehr starke 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;}' | sortund die Standardausgaben jedes Programms mit der Standardeingabe des nächsten Programms in der Pipeline zu verknüpfen.

Zweitens habe ich die Standard-ISO-C-Funktionen für die Arbeit mit Dateistreams ( FILE *Objekten) angegeben. Auf Kernelebene sind dies alle Dateideskriptoren ( intVerweise auf die Dateitabelle) und viele Operationen auf niedrigerer Ebene wie readund write, die dies nicht tun Machen Sie die glückliche Pufferung der ISO C-Funktionen. Ich dachte, es einfach zu halten und die einfacheren Funktionen zu verwenden, aber ich dachte trotzdem, Sie sollten die Alternativen kennen. :) :)

Sarnold
quelle
Wenn der Prozess ausgeführt wird, schreibt er Fehler in diese stderr-Datei oder wenn das Programm aus seiner Quelle kompiliert wird. Auch wenn wir aus der Sicht des Compilers über diese Dateien sprechen, ist es anders als wenn man sie beispielsweise mit einem Programm vergleicht?
Shouvik
1
@Shouvik, der Compiler ist nur ein weiteres Programm mit einem eigenen stdin, stdout und stderr. Wenn der Compiler Warnungen oder Fehler schreiben muss, schreibt er diese in stderr. Wenn das Compiler-Frontend Zwischencode für den Assembler ausgibt, schreibt es möglicherweise den Zwischencode auf stdout und der Assembler akzeptiert möglicherweise seine Eingabe auf stdin, aber alles, was sich aus Ihrer Sicht als Benutzer hinter den Kulissen befindet.) Sobald Sie dies getan haben Als kompiliertes Programm kann dieses Programm auch Fehler in seinen Standardfehler schreiben, hat aber nichts mit dem Kompilieren zu tun.
Sarnold
Vielen Dank für diese Informationen. Ich denke, es ist ziemlich dumm von mir, es sowieso nicht in dieser Perspektive zu sehen ...: P
Shouvik
1
Sie sagen also, dass Standard uns hilft, das Programm zu drucken
babygame0ver
9

stdin

Liest Eingaben über die Konsole (z. B. Tastatureingabe). Wird in C mit scanf verwendet

scanf(<formatstring>,<pointer to storage> ...);

stdout

Erzeugt eine Ausgabe an die Konsole. Wird in C mit printf verwendet

printf(<string>, <values to print> ...);

stderr

Erzeugt eine 'Fehler'-Ausgabe an die Konsole. Wird in C mit fprintf verwendet

fprintf(stderr, <string>, <values to print> ...);

Umleitung

Die Quelle für stdin kann umgeleitet werden. Anstatt von der Tastatureingabe zu stammen, kann es beispielsweise aus einer Datei ( echo < file.txt) oder einem anderen Programm ( ps | grep <userid>) stammen.

Die Ziele für stdout, stderr können ebenfalls umgeleitet werden. Zum Beispiel kann stdout in eine Datei umgeleitet werden: ls . > ls-output.txtIn diesem Fall wird die Ausgabe in die Datei geschrieben ls-output.txt. Stderr kann mit umgeleitet werden 2>.

mikek3332002
quelle
8

Ich denke, Leute, die sagen, stderrdass sie nur für Fehlermeldungen verwendet werden sollten, sind irreführend.

Es sollte auch für informative Nachrichten verwendet werden, die für den Benutzer bestimmt sind, der den Befehl ausführt, und nicht für potenzielle nachgeschaltete Verbraucher der Daten (dh wenn Sie eine Shell-Pipe ausführen, die mehrere Befehle verkettet, möchten Sie keine informativen Nachrichten wie "Abrufen von Element 30 von" 42424 "wird angezeigt, stdoutda sie den Verbraucher verwirren. Möglicherweise möchten Sie jedoch, dass der Benutzer sie sieht.

Siehe dies für historische Gründe:

"Alle Programme stellten eine Diagnose auf die Standardausgabe. Dies hatte immer Probleme verursacht, wenn die Ausgabe in eine Datei umgeleitet wurde, wurde jedoch unerträglich, wenn die Ausgabe an einen ahnungslosen Prozess gesendet wurde. Trotzdem war sie nicht bereit, die Einfachheit der Standardeingabe zu verletzen. Standardausgabemodell, Menschen tolerierten diesen Zustand durch v6. Kurz danach schnitt Dennis Ritchie den gordischen Knoten durch die Einführung der Standardfehlerdatei ab. Das war nicht genug. Mit Pipelines konnte die Diagnose von mehreren Programmen gleichzeitig ausgeführt werden. Diagnose erforderlich sich identifizieren. "

dee
quelle
3

Die Verwendung von ps -aux zeigt aktuelle Prozesse an, die alle in / proc / as / proc / (pid) / aufgeführt sind. Durch Aufrufen von cat / proc / (pid) / fd / 0 wird alles gedruckt, was in der Standardausgabe von gefunden wird diesen Prozess denke ich. Also vielleicht,

/ proc / (pid) / fd / 0 - Standardausgabedatei
/ proc / (pid) / fd / 1 - Standardeingabedatei
/ proc / (pid) / fd / 2 - Standardfehlerdatei

beispielsweisemein Terminalfenster

Aber nur für / bin / bash funktionierte dies gut. Andere Prozesse hatten im Allgemeinen nichts in 0, aber viele hatten Fehler in 2 geschrieben

Sam
quelle
3

Informationen zu diesen Dateien finden Sie in den Manpages. Führen Sie den Befehl auf Ihrem Terminal aus.

$ man stdout 

Für eine einfache Antwort ist jede Datei für:

Standard für einen Stream aus

stdin für eine Stream-Eingabe

stderr zum Drucken von Fehlern oder Protokollmeldungen.

Jedes Unix-Programm hat jeden dieser Streams.

Margach Chris
quelle
2

stderr führt keine E / A-Cache-Pufferung durch. Wenn unsere Anwendung wichtige Nachrichteninformationen (einige Fehler, Ausnahmen) zur Konsole oder zur Datei drucken muss, verwenden Sie diese, wenn Sie stdout zum Drucken allgemeiner Protokollinformationen verwenden, da die E / A-Cache-Pufferung verwendet wird, besteht die Möglichkeit, dass Vor dem Schreiben unserer Nachrichten in die Dateianwendung wird möglicherweise geschlossen, wodurch das Debuggen komplex wird

Geekanil
quelle
0

Eine Datei mit zugehöriger Pufferung wird als Stream bezeichnet und als Zeiger auf einen definierten Typ FILE deklariert. Die Funktion fopen () erstellt bestimmte beschreibende Daten für einen Stream und gibt einen Zeiger zurück, um den Stream in allen weiteren Transaktionen zu bestimmen. Normalerweise gibt es drei offene Streams mit konstanten Zeigern, die im Header deklariert und den geöffneten Standarddateien zugeordnet sind. Beim Programmstart sind drei Streams vordefiniert und müssen nicht explizit geöffnet werden: Standardeingabe (zum Lesen herkömmlicher Eingaben), Standardausgabe (zum Schreiben herkömmlicher Ausgaben) und Standardfehler (zum Schreiben diagnostischer Ausgaben). Beim Öffnen ist der Standardfehlerstrom nicht vollständig gepuffert. Die Standardeingabe- und Standardausgabestreams werden genau dann vollständig gepuffert, wenn festgestellt werden kann, dass sich der Stream nicht auf ein interaktives Gerät bezieht

https://www.mkssoftware.com/docs/man5/stdio.5.asp

Bahruz Balabayov
quelle