web-dev-qa-db-fra.com

Les rapports de progression / informations de journalisation appartiennent-ils à stderr ou stdout?

Existe-t-il un POSIX, GNU officiel ou une autre directive sur l'endroit où les rapports d'avancement et les informations de journalisation (des choses comme "Faire du foo; foo done") doivent être imprimés? Personnellement, j'ai tendance à les écrire sur stderr pour pouvoir rediriger stdout et obtenir uniquement la sortie réelle du programme. On m'a récemment dit que ce n'était pas une bonne pratique car les rapports d'avancement ne sont pas en fait des erreurs et seuls les messages d'erreur doivent être imprimés sur stderr.

Les deux positions ont du sens, et bien sûr, vous pouvez choisir l'une ou l'autre en fonction des détails de ce que vous faites, mais j'aimerais savoir s'il existe une norme communément admise pour cela. Je n'ai pas pu trouver de règles spécifiques dans POSIX, les normes de codage GNU, ou toute autre liste de bonnes pratiques largement acceptée.

Nous avons quelques questions similaires, mais elles ne répondent pas à ce problème précis:

Alors, y a-t-il des règles officielles sur l'endroit où les rapports d'avancement et autres messages informatifs (qui ne font pas partie des résultats réels du programme) doivent être imprimés?

79
terdon

Posix définit les flux standard donc :

Au démarrage du programme, trois flux doivent être 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 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.

Bibliothèque GNU C décrit les flux standard de la même manière:

Variable: [~ # ~] fichier [~ # ~] * stdout
Le flux de sortie standard, qui est utilisé pour la sortie normale du programme.

Variable: [~ # ~] fichier [~ # ~] * stderr
Le flux d'erreur standard, qui est utilisé pour les messages d'erreur et les diagnostics émis par le programme.

Ainsi, les définitions standard ont peu d'indications pour l'utilisation des flux au-delà de "sortie conventionnelle/normale" et "sortie de diagnostic/erreur". En pratique, il est courant de rediriger l'un ou les deux de ces flux vers des fichiers et des pipelines, où les indicateurs de progression seront un problème. Certains systèmes ont même moniteurstderr pour la sortie et le considèrent comme un signe de problème. Les informations de progression purement auxiliaires sont donc problématiques sur les deux flux.

Au lieu d'envoyer inconditionnellement des indicateurs de progression à soit flux standard, il est important de reconnaître que la sortie de progression ne convient qu'aux flux interactif. Dans cet esprit, je recommande d'écrire des compteurs de progression uniquement après avoir vérifié si le flux est interactif (par exemple, avec isatty() ) ou lorsqu'il est explicitement activé par une option de ligne de commande. Cela est particulièrement important pour les indicateurs de progression qui s'appuient sur le comportement de mise à jour du terminal pour avoir un sens, comme les barres% complétées.

Pour certains messages de progression très simples ("Démarrage de X" ... "Terminé avec X"), il est plus raisonnable d'inclure la sortie même pour les flux non interactifs. Dans ce cas, réfléchissez à la manière dont les utilisateurs pourraient interagir avec les flux, comme rechercher avec grep ou paginer avec less ou surveiller avec tail -f. S'il est logique de voir les messages de progression dans ces contextes, ils seront beaucoup plus faciles à consommer depuis stdout.

28
Bradd Szonye

POSIX définit l'erreur standard comme

pour écrire une sortie de diagnostic

Cela ne limite pas son utilisation aux seuls messages d'erreur. Je considérerais les informations de progression comme une sortie de diagnostic, elles appartiennent donc à l'erreur standard.

74
Stephen Kitt

POSIX est un peu plus concret sur les "informations de diagnostic" dans Shell et utilitaires, 1.4: Valeurs par défaut de la description de l'utilitaire (accent sur le mien):

STDERR

La section STDERR décrit la sortie d'erreur standard de l'utilitaire. Seuls les messages envoyés à dessein par l'utilitaire sont décrits. L'utilisation d'un terminal pour l'erreur standard peut entraîner l'arrêt de l'un des utilitaires standard qui écrivent la sortie d'erreur standard lorsqu'il est utilisé en arrière-plan. Pour cette raison, les applications ne doivent pas utiliser de fonctionnalités interactives dans les scripts à placer en arrière-plan.

Le format des messages de diagnostic pour la plupart des utilitaires n'est pas spécifié, mais le langage et les conventions culturelles des messages de diagnostic et d'information dont le format n'est pas spécifié par ce volume de POSIX.1-2008 doivent être affectés par le réglage de LC_MESSAGES et [XSI] [Option Start ] NLSPATH. [Fin de l'option]

La sortie d'erreur standard spécifiée des utilitaires standard ne doit pas dépendre de l'existence ou de la valeur des variables d'environnement définies dans ce volume de POSIX.1-2008, sauf indication contraire de ce volume de POSIX.1-2008.

Comportement par défaut : Lorsque cette section est répertoriée comme "L'erreur standard ne doit être utilisée que pour les messages de diagnostic.", Cela signifie que, sauf indication contraire, les messages de diagnostic doivent être envoyés à l'erreur standard uniquement lorsque l'état de sortie indique qu'une erreur s'est produite et que l'utilitaire est utilisé comme décrit dans ce volume de POSIX.1-2008.

Lorsque cette section est répertoriée comme "Non utilisé", cela signifie que l'erreur standard ne doit pas être utilisée lorsque l'utilitaire est utilisé comme décrit dans ce volume de POSIX.1-2008.

IANASL, mais j'interprète cela comme signifiant que stderr n'aura de sortie que si l'utilitaire retournera un code de sortie d'erreur. Étant donné que cela ne doit pas être le cours normal des événements pour une exécution réussie, aucune information de progression ne doit être imprimée par un utilitaire POSIX sauf si une erreur se produit (sauf, si cours, autrement spécifié, etc.).

10
muru

Par le principe d'exclusion, il ne peut aller qu'à stderr. Oui, je sais que vous avez posé des questions sur une spécification officielle, que je ne peux pas vous présenter au-delà du lien vers la spécification POSIX, donnée par Stephen Kitt, qui stipule que stderr est à des fins de diagnostic.

Le point le plus important est que stdin et stdout ont une fonction qui interdit l'impression des rapports de progression sur stdout - ils forment bien sûr la séquence de tuyaux qui, dans les commandes Unix Shell, n'est pas seulement un effet secondaire, mais le cœur même de la puissante approche de pipelining .

Donc. Rien à part la véritable "charge utile" de votre programme n'appartient à stdout. Si votre programme n'a pas de sortie, rien ne devrait aller à stdout. Cela laisse stderr pour tout le reste, y compris les rapports d'avancement.

Certes, cela laisse un trou - il serait probablement agréable d'avoir un "stdfluff" ou quelque chose comme ça qui n'est ni pour la sortie, ni pour les erreurs, mais pour les rapports d'avancement, le débogage et quelque chose du genre. En fait, rien ne vous empêche de le faire, c'est-à-dire que vous pouvez imprimer votre progression dans le descripteur de fichier 3. Exemple:

$ Perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'

Cela ne produit aucune sortie. (*)

$ Perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'  3>&1
hello

Cela s'imprime sur fd-3, qui est redirigé vers stdout.

(*) Le premier exemple ne produit aucune sortie mais est encore un peu tiré par les cheveux; open échoue et $! contiendrait no such file or directory; prenez juste ceci comme exemple, ce n'est bien sûr pas un usage sérieux. Dans un programme réel, si vous vouliez suivre cette voie, vous pourriez tester si /dev/fd/3 est utilisable et prenez cela comme une indication de l'activation de vos rapports d'avancement; vous devriez le faire assez tôt pour ne pas être dérouté par vos propres opens pour de vrais fichiers et autres ...

9
AnoE