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 vongrep
.
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