Il serait plus correct de dire que stdin
, stdout
, et stderr
sont des "flux d'E/S" plutôt que des fichiers. Comme vous l'avez remarqué, ces entités ne résident pas dans le système de fichiers. Mais la philosophie Unix, en ce qui concerne les entrées/sorties, est "tout est un fichier". En pratique, cela signifie vraiment que vous pouvez utiliser les mêmes fonctions et interfaces de bibliothèque (printf
,scanf
, read
, write
, select
, etc.) sans se soucier de savoir si le flux d'E/S est connecté à un clavier, un fichier disque, un socket, un tube ou une autre abstraction d'E/S.
La plupart des programmes ont besoin de lire les entrées, d'écrire les sorties et de consigner les erreurs, donc stdin
, stdout
, et stderr
sont prédéfinis pour vous, comme commodité de programmation. Ceci n'est qu'une convention et n'est pas appliqué par le système d'exploitation.
Je crains que votre compréhension ne soit complètement à l'envers. :)
Pensez à "entrée standard", "sortie standard" et "erreur standard" du programme point de vue, pas du point de vue du noyau.
Lorsqu'un programme a besoin d'imprimer une sortie, il imprime normalement en "sortie standard". Un programme imprime généralement la sortie vers la sortie standard avec printf
, qui imprime UNIQUEMENT sur la sortie standard.
Lorsqu'un programme a besoin d'imprimer des informations d'erreur (pas nécessairement des exceptions, il s'agit d'une construction de langage de programmation, imposée à un niveau beaucoup plus élevé), il imprime normalement "l'erreur standard". Il le fait normalement avec fprintf
, qui accepte un flux de fichiers à utiliser lors de l'impression. Le flux de fichier peut être n'importe quel fichier ouvert en écriture :sortie standard, erreur standard ou tout autre fichier ouvert avec fopen
ou fdopen
.
"standard in" est utilisé lorsque le fichier doit lire l'entrée, en utilisant fread
ou fgets
, ou getchar
.
N'importe lequel de ces fichiers peut être facilement redirigé depuis le shell, comme ceci :
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
Ou toute l'enchilada :
cat < /etc/passwd > /tmp/out 2> /tmp/err
Il y a deux mises en garde importantes :premièrement, "entrée standard", "sortie standard" et "erreur standard" ne sont qu'une convention. Ils sont très forts convention, mais c'est juste un accord sur le fait qu'il est très agréable de pouvoir exécuter des programmes comme celui-ci :grep echo /etc/services | awk '{print $2;}' | sort
et avoir les sorties standard de chaque programme accrochées à l'entrée standard du programme suivant dans le pipeline.
Deuxièmement, j'ai donné les fonctions ISO C standard pour travailler avec des flux de fichiers (FILE *
objets) -- au niveau du noyau, ce sont tous les descripteurs de fichiers (int
références à la table de fichiers) et des opérations de niveau beaucoup plus bas comme read
et write
, qui ne font pas l'heureuse mise en mémoire tampon des fonctions ISO C. Je pensais rester simple et utiliser les fonctions les plus simples, mais je pensais tout de même que vous devriez connaître les alternatives. :)
Saisie standard - c'est le nom du fichier que votre processus lit pour obtenir des informations de votre part.
Sortie standard - votre processus écrit une sortie conventionnelle dans ce descripteur de fichier.
Erreur type - votre processus écrit la sortie de diagnostic dans ce descripteur de fichier.
C'est à peu près aussi stupide que possible :-)
Bien sûr, c'est surtout par convention. Rien ne vous empêche d'écrire vos informations de diagnostic sur la sortie standard si vous le souhaitez. Vous pouvez même fermer totalement les trois descripteurs de fichiers et ouvrir vos propres fichiers pour les E/S.
Lorsque votre processus démarre, ces poignées doivent déjà être ouvertes et il peut simplement y lire et/ou y écrire.
Par défaut, ils sont probablement connectés à votre terminal (par exemple, /dev/tty
) mais les shells vous permettront de mettre en place des connexions entre ces handles et des fichiers et/ou périphériques spécifiques (ou même des pipelines vers d'autres processus) avant que votre processus ne démarre (certaines des manipulations possibles sont plutôt astucieuses).
Un exemple étant :
my_prog <inputfile 2>errorfile | grep XYZ
qui :
- créer un processus pour
my_prog
. - ouvrir
inputfile
comme entrée standard (descripteur de fichier 0). - ouvrir
errorfile
comme erreur standard (descripteur de fichier 2). - créer un autre processus pour
grep
. - joindre la sortie standard de
my_prog
à l'entrée standard degrep
.
Concernant votre commentaire :
Lorsque j'ouvre ces fichiers dans le dossier /dev, comment se fait-il que je ne voie jamais la sortie d'un processus en cours d'exécution ?
C'est parce que ce ne sont pas des fichiers normaux. Alors qu'UNIX présente tout en tant que fichier dans un système de fichiers quelque part, cela ne le rend pas aux niveaux les plus bas. La plupart des fichiers dans le /dev
hiérarchie sont des périphériques caractère ou bloc, en fait un pilote de périphérique. Ils n'ont pas de taille, mais ils ont un numéro d'appareil majeur et mineur.
Lorsque vous les ouvrez, vous êtes connecté au pilote de périphérique plutôt qu'à un fichier physique, et le pilote de périphérique est suffisamment intelligent pour savoir que des processus distincts doivent être gérés séparément.
Il en est de même pour Linux /proc
système de fichiers. Ce ne sont pas de vrais fichiers, juste des passerelles étroitement contrôlées vers les informations du noyau.
En complément des réponses ci-dessus, voici un résumé des redirections :
EDIT :Ce graphique n'est pas tout à fait correct.
Le premier exemple n'utilise pas du tout stdin, il passe "hello" comme argument à la commande echo.
Le graphique indique également que 2>&1 a le même effet que &> cependant
ls Documents ABC > dirlist 2>&1
#does not give the same output as
ls Documents ABC > dirlist &>
C'est parce que &> nécessite un fichier vers lequel rediriger, et 2>&1 envoie simplement stderr dans stdout