Confus au sujet de stdin, stdout et stderr?

230

Je suis plutôt confus avec le but de ces trois fichiers. Si ma compréhension est correcte, stdinest le fichier dans lequel un programme écrit dans ses demandes pour exécuter une tâche dans le processus, stdoutest le fichier dans lequel le noyau écrit sa sortie et le processus qui le demande accède aux informations, et stderrest le fichier dans où toutes les exceptions sont saisies. En ouvrant ces fichiers pour vérifier s'ils se produisent réellement, je n'ai rien trouvé à suggérer!

Ce que je voudrais savoir, c'est quel est exactement le but de ces fichiers, réponse absolument stupide avec très peu de jargon technique!

Shouvik
la source
36
Observation: Cette question était acceptable en 2010, mais serait déclassée très rapidement de nos jours.
byxor
3
@Brandon Pouvez-vous fournir une raison? Je pense que ce serait utile pour votre commentaire.
Indépendant
3
@byxor pour être juste, je vais demander: le post d'Op demandait-il aux gens de l'aider à déboguer son code? il semble que Shouvik ait posé une question concernant le but de stdin, stdout et stderr. le poste de l'op semble être par curiosité, non? (j'apprends en fait moi-même cette atmosphère. merci, SO, pour ne pas avoir supprimé ce post)
sansae
2
@ user123456 vous avez raison. J'apprenais à être développeur de logiciels et les S / O à l'époque étaient un excellent endroit pour apprendre la programmation. Nous voulions à l'origine qu'il soit un service wiki de type pour toutes les questions informatiques. #juniorDevForLife
Shouvik
3
@Shouvik merci pour ce morceau d'histoire. J'apprends aussi à être développeur de logiciels (je viens d'être accepté dans un camp sympa en SF). Je suis encore relativement nouveau sur S / O et je ne suis toujours pas sûr de ce que je peux et ne peux pas publier. Je trouve que la modération ici peut être assez stricte. J'aime cette balise de hachage. #juniorDevForLife. Je voudrais vous pm au lieu de commenter ici car cela n'ajoute rien à la discussion, mais je ne crois pas que S / O ait un système pm. Passez une bonne journée.
sansae

Réponses:

251

Entrée standard - il s'agit du descripteur de fichier que votre processus lit pour obtenir des informations de votre part.

Sortie standard - votre processus écrit des informations normales dans ce descripteur de fichier.

Erreur standard - votre processus écrit des informations d'erreur dans ce descripteur de fichier.

C'est à peu près aussi stupide que possible :-)

Bien sûr, c'est principalement par convention. Rien ne vous empêche d'écrire vos informations d'erreur 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, il doit déjà avoir ces poignées ouvertes et il peut simplement y lire et / ou y écrire.

Par défaut, ils sont probablement connectés à votre périphérique terminal (par exemple, /dev/tty) mais les shells vous permettront de configurer des connexions entre ces poignées et des fichiers et / ou périphériques spécifiques (ou même des pipelines vers d'autres processus) avant le démarrage de votre processus (certains les manipulations possibles sont plutôt astucieuses).

Un exemple étant:

my_prog <inputfile 2>errorfile | grep XYZ

Qui va:

  • créer un processus pour my_prog.
  • ouvrir inputfilecomme entrée standard (descripteur de fichier 0).
  • ouvrir errorfilecomme votre erreur standard (descripteur de fichier 2).
  • créer un autre processus pour grep.
  • attachez la sortie standard de my_progà l'entrée standard de grep.

Re votre commentaire:

Lorsque j'ouvre ces fichiers dans le dossier / dev, comment se fait-il que je n'arrive jamais à voir 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 sous forme de fichier dans un système de fichiers quelque part, cela ne le fait pas aux niveaux les plus bas. La plupart des fichiers de la /devhiérarchie sont des périphériques de type 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 traités séparément.

Il en va de même pour le système de /procfichiers Linux . Ce ne sont pas de vrais fichiers, juste des passerelles étroitement contrôlées vers les informations du noyau.

paxdiablo
la source
1
C'est pour votre réponse. Bien que je puisse comprendre le but des fichiers à partir de ce que vous décrivez, je voudrais déplacer un niveau de plus. lorsque j'ouvre ces fichiers dans le dossier / dev, comment se fait-il que je ne puisse jamais voir la sortie d'un processus en cours d'exécution. Supposons que j'exécute top sur le terminal, n'est-il pas censé produire ses résultats sur le fichier stdout périodiquement, donc quand il est mis à jour, je devrais être en mesure de voir une instance de la sortie imprimée sur ce fichier. Mais ce n'est pas le cas. Ces fichiers ne sont donc pas les mêmes (ceux du répertoire / dev).
Shouvik
7
Parce que ce ne sont pas des fichiers techniques. Ce sont des nœuds de périphérique, indiquant un périphérique spécifique sur lequel écrire. UNIX peut présenter tout pour vous une abstraction de fichier , mais cela ne fait pas ainsi aux niveaux les plus profonds.
paxdiablo
1
Utilisez la fonction de redirection du shell. xyz >xyz.outva écrire votre sortie standard dans un fichier physique qui peut être lu par d'autres processus. xyz | grep somethingconnectera xyzstdout à grepstdin plus directement. Si vous voulez un accès sans entrave à un processus que vous ne contrôlez pas de cette façon, vous devrez regarder quelque chose comme /procou écrire du code pour filtrer la sortie en vous connectant au noyau d'une manière ou d'une autre. Il peut y avoir d'autres solutions mais elles sont probablement toutes aussi dangereuses les unes que les autres :-)
paxdiablo
20
@Shouvik, notez qu'il /dev/stdins'agit d'un lien symbolique vers /proc/self/fd/0- le premier descripteur de fichier ouvert par le programme en cours d'exécution. Ainsi, ce qui est indiqué par /dev/stdinchangera d'un programme à l'autre, car /proc/self/pointe toujours vers le «programme en cours d'exécution». (Quel que soit le programme qui fait l' openappel.) /dev/stdinEt des amis ont été mis là pour rendre les scripts shell setuid plus sûrs, et vous permettent de passer le nom /dev/stdinde fichier aux programmes qui ne fonctionnent qu'avec des fichiers, mais que vous souhaitez contrôler de manière plus interactive. (Un jour, ce sera un truc utile pour vous de savoir. :)
sarnold
1
@ CarlosW.Mercado, un fichier est une manifestation physique des données. Par exemple, les bits stockés sur le disque dur. Une poignée de fichier est (généralement) un petit jeton utilisé pour faire référence à ce fichier, une fois que vous l'avez ouvert.
paxdiablo
62

Il serait plus correct de dire cela stdin, stdoutet ce stderrsont des "flux d'E / S" plutôt que des fichiers. Comme vous l'avez remarqué, ces entités ne vivent pas dans le système de fichiers. Mais la philosophie Unix, en ce qui concerne les E / S, est "tout est un fichier". En pratique, cela signifie vraiment que vous pouvez utiliser les mêmes fonctions de bibliothèque et interfaces ( printf, scanf, read, write, select, etc.) sans se soucier de savoir si le flux d' E / S est connecté à un clavier, un fichier de disque, une prise, un tuyau, ou une autre abstraction d'E / S.

La plupart des programmes doivent lire l' entrée, la sortie d'écriture, et les erreurs de journal, donc stdin, stdoutet stderrsont pour vous prédéfinis, comme une commodité de programmation. Il ne s'agit que d'une convention et n'est pas appliqué par le système d'exploitation.

Jim Lewis
la source
Merci pour vos contributions. Souhaitez-vous savoir comment je pourrais intercepter le flux de données de sortie d'un processus et le produire dans un fichier à moi?
Shouvik
51

En complément des réponses ci-dessus, voici un résumé des redirections: Cheatsheet de redirections

EDIT: Ce graphique n'est pas entièrement correct mais je ne sais pas pourquoi ...

Le graphique indique 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 &>
Léopold Gault
la source
4
Votre commentaire combiné avec la réponse acceptée est parfaitement logique et explique clairement les choses! Merci!
Mykola
1
Une image vaut mieux que mille mots !
tauseef_CuriousGuy
22

J'ai bien peur que votre compréhension soit complètement à l'envers. :)

Pensez à «entrée standard», «sortie standard» et «erreur standard» du point de vue du programme , et non du point de vue du noyau.

Lorsqu'un programme doit imprimer une sortie, il imprime normalement en "sortie standard". Un programme imprime généralement la sortie en sortie standard avec printf, qui imprime UNIQUEMENT en sortie standard.

Lorsqu'un programme doit imprimer des informations sur les erreurs (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 en "erreur standard". Il le fait normalement avec fprintf, qui accepte un flux de fichiers à utiliser lors de l'impression. Le flux de fichiers peut être tout fichier ouvert en écriture: sortie standard, erreur standard ou tout autre fichier ouvert avec fopenou fdopen.

"standard in" est utilisé lorsque le fichier doit lire l'entrée, en utilisant freadou 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. C'est une convention très forte , mais tout cela n'est qu'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;}' | sortet d'avoir les sorties standard de chaque programme connectées à l'entrée standard du programme suivant dans le pipeline.

Deuxièmement, j'ai donné les fonctions ISO C standard pour travailler avec les flux de fichiers ( FILE *objets) - au niveau du noyau, ce sont tous les descripteurs de fichiers ( intréférences à la table de fichiers) et des opérations de niveau beaucoup plus bas comme readet write, qui ne le font pas faire le tampon heureux des fonctions ISO C. J'ai pensé à rester simple et à utiliser les fonctions les plus faciles, mais je pensais tout de même que vous devriez connaître les alternatives. :)

sarnold
la source
Il en est de même lorsque le processus est en cours d'exécution qu'il écrit des erreurs dans ce fichier stderr ou lorsque le programme est en cours de compilation à partir de sa source. De plus, lorsque nous parlons de ces fichiers du point de vue du compilateur, est-ce différent de celui comparé à, disons, un programme?
Shouvik
1
@Shouvik, le compilateur est juste un autre programme, avec ses propres stdin, stdout et stderr. Lorsque le compilateur doit écrire des avertissements ou des erreurs, il les écrit dans stderr. Lorsque le compilateur frontal génère du code intermédiaire pour l'assembleur, il peut écrire le code intermédiaire sur stdout et l'assembleur peut accepter son entrée sur stdin, mais tout cela serait en coulisses de votre point de vue en tant qu'utilisateur.) Une fois que vous avez un programme compilé, ce programme peut également écrire des erreurs dans son erreur standard, mais il n'a rien à voir avec la compilation.
sarnold
Merci pour ce jeton d'informations. Je suppose que c'est assez stupide de ma part de ne pas le voir dans cette perspective de toute façon ...: P
Shouvik
1
Vous dites donc que la norme nous aide à imprimer le programme
babygame0ver
9

stdin

Lit les entrées via la console (par exemple, entrée clavier). Utilisé en C avec scanf

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

stdout

Produit une sortie vers la console. Utilisé en C avec printf

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

stderr

Produit une sortie «erreur» vers la console. Utilisé en C avec fprintf

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

Redirection

La source de stdin peut être redirigée. Par exemple, au lieu de provenir d'une saisie au clavier, il peut provenir d'un fichier ( echo < file.txt) ou d'un autre programme ( ps | grep <userid>).

Les destinations pour stdout, stderr peuvent également être redirigées. Par exemple, stdout peut être redirigé vers un fichier: ls . > ls-output.txtdans ce cas, la sortie est écrite dans le fichier ls-output.txt. Stderr peut être redirigé avec 2>.

mikek3332002
la source
8

Je pense que les gens qui disent qu'il stderrne faut utiliser que des messages d'erreur sont trompeurs.

Il doit également être utilisé pour les messages informatifs destinés à l'utilisateur exécutant la commande et non à tout consommateur potentiel en aval des données (c'est-à-dire que si vous exécutez un pipe shell chaînant plusieurs commandes, vous ne voulez pas de messages informatifs comme "obtenir l'élément 30 de 42424 "pour apparaître stdoutcar ils vont dérouter le consommateur, mais vous souhaiterez peut-être tout de même que l'utilisateur les voie.

Voir ceci pour une justification historique:

"Tous les programmes ont placé des diagnostics sur la sortie standard. Cela avait toujours causé des problèmes lorsque la sortie était redirigée vers un fichier, mais était devenu intolérable lorsque la sortie était envoyée à un processus sans méfiance. Néanmoins, ne voulant pas violer la simplicité de l'entrée standard- modèle de sortie standard, les gens ont toléré cet état de choses via la version 6. Peu de temps après, Dennis Ritchie a coupé le nœud gordien en introduisant le fichier d'erreur standard. Ce n'était pas tout à fait suffisant. Avec les pipelines, les diagnostics pouvaient provenir de plusieurs programmes exécutés simultanément. Diagnostics nécessaires de s'identifier. "

dee
la source
3

L'utilisation de ps -aux révèle les processus actuels, qui sont tous répertoriés dans / proc / as / proc / (pid) /, en appelant cat / proc / (pid) / fd / 0, il imprime tout ce qui se trouve dans la sortie standard de ce processus, je pense. Alors peut être,

/ proc / (pid) / fd / 0 - Fichier de sortie standard
/ proc / (pid) / fd / 1 - Fichier d'entrée standard
/ proc / (pid) / fd / 2 - Fichier d'erreur standard

par exemplema fenêtre de terminal

Mais cela ne fonctionnait bien que pour / bin / bash, d'autres processus n'avaient généralement rien en 0 mais beaucoup avaient des erreurs écrites en 2

Sam
la source
3

Pour obtenir des informations faisant autorité sur ces fichiers, consultez les pages de manuel, exécutez la commande sur votre terminal.

$ man stdout 

Mais pour une réponse simple, chaque fichier est pour:

sortie standard pour un stream out

stdin pour une entrée de flux

stderr pour les erreurs d'impression ou les messages de journal.

Chaque programme Unix possède chacun de ces flux.

Margach Chris
la source
2

stderr ne fera pas de mise en mémoire tampon du cache d'E / S. Si notre application a besoin d'imprimer des informations de message critiques (certaines erreurs, exceptions) pour la console ou pour les utiliser, utilisez stdout pour imprimer les informations générales du journal lors de l'utilisation de la mémoire tampon du cache d'E / S, il y a une chance que avant d'écrire nos messages dans un fichier, l'application peut se fermer, ce qui laisse un débogage complexe

geekanil
la source
0

Un fichier avec la mise en mémoire tampon associée est appelé un flux et est déclaré être un pointeur vers un fichier de type défini. La fonction fopen () crée certaines données descriptives pour un flux et renvoie un pointeur pour désigner le flux dans toutes les transactions ultérieures. Normalement, il y a trois flux ouverts avec des pointeurs constants déclarés dans l'en-tête et associés aux fichiers ouverts standard. Au démarrage du programme, trois flux sont prédéfinis et n'ont pas besoin d'être ouverts explicitement: entrée standard (pour lire l'entrée conventionnelle), sortie standard (pour écrire la sortie conventionnelle) et erreur standard (pour écrire la sortie de diagnostic). Lorsqu'il est ouvert, le flux d'erreur standard n'est pas entièrement mis en mémoire tampon; les flux d'entrée et de sortie standard sont entièrement tamponnés si et seulement si le flux peut être déterminé comme ne faisant pas référence à un appareil interactif

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

Bahruz Balabayov
la source