GNU/Linux >> Tutoriels Linux >  >> Linux

Confus à propos de stdin, stdout et stderr ?

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 de grep .

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


Linux
  1. Sortie vers Stdout et en même temps Grep dans un fichier ?

  2. Manière de rediriger la sortie d'un programme et de l'avoir toujours sur Stdout ?

  3. Comment rediriger la sortie vers un fichier et stdout

  4. Comment rediriger stderr et stdout vers différents fichiers dans la même ligne de script ?

  5. Tuyauterie stdout et stderr à l'intérieur d'une règle Makefile

Comment rediriger stderr vers stdout dans Bash

Rediriger toutes les sorties vers un fichier dans Bash

Echo à la fois stdout et stderr

Est-il sûr de désactiver la mise en mémoire tampon avec stdout et stderr ?

echo ou print /dev/stdin /dev/stdout /dev/stderr

Capture de STDERR et STDOUT dans un fichier à l'aide de tee