Gehören Fortschrittsberichte / Protokollinformationen zu stderr oder stdout?

75

Gibt es eine offizielle POSIX-, GNU- oder andere Richtlinie, in der Fortschrittsberichte und Protokollinformationen (z. B. "Doing foo; foo done") gedruckt werden sollten? Persönlich neige ich dazu, sie an stderr zu schreiben, damit ich stdout umleiten und nur die tatsächliche Ausgabe des Programms erhalten kann. Mir wurde kürzlich gesagt, dass dies keine gute Praxis ist, da Fortschrittsberichte eigentlich keine Fehler sind und nur Fehlermeldungen an stderr gedruckt werden sollten.

Beide Positionen sind sinnvoll, und natürlich können Sie die eine oder die andere auswählen, je nachdem, was Sie im Detail tun, aber ich würde gerne wissen, ob es dafür einen allgemein akzeptierten Standard gibt. Ich konnte in POSIX, den GNU-Codierungsstandards oder anderen allgemein akzeptierten Listen mit Best Practices keine spezifischen Regeln finden.

Wir haben ein paar ähnliche Fragen, die sich jedoch nicht genau mit diesem Thema befassen:

Gibt es also offizielle Regeln, wo Fortschrittsberichte und andere informative Nachrichten (die nicht Teil der tatsächlichen Ausgabe des Programms sind) gedruckt werden sollen?

terdon
quelle
26
Das Drucken von Spinnern und dergleichen stdoutzusammen mit den Ergebnissen ist ein sicherer Weg, um die Ergebnisse unbrauchbar zu machen. Wenn Sie die Ergebnisse jemals an ein anderes Programm weiterleiten müssen, muss dieses Programm die Ergebnisse von den Spinnern trennen. Wenn Sie die Ausgabe in eine Datei umleiten, werden die Drehfelder nicht angezeigt. MEINER BESCHEIDENEN MEINUNG NACH.
Satō Katsura,
2
@SatoKatsura ja, das ist auch meine meinung und deswegen drucke ich so auf stderr. Der CTO der Firma, für die ich arbeite, ist jedoch der Ansicht, dass das Drucken nach stderr ein Hinweis darauf ist, dass etwas schief gelaufen ist. Ich habe die mutige Behauptung aufgestellt, dass der POSIX Way® nach stderr druckt, und er hat mich darauf aufmerksam gemacht. Angesichts der Tatsache, dass er über 20 Jahre Erfahrung verfügt, würde ich gerne sehen, ob ich eine Art "offiziellen" Leitfaden finden kann.
terdon
stdoutGenau wie Sato Katsura sagte, ist dies ein sicherer und richtiger Weg, um Spinner und andere informative Botschaften auszudrücken, aber wie viele Programmierer sagen, ist Schweigen Gold wert. Gib nichts aus, wenn alles in Ordnung ist. ' so in der Tat ist stderr immer verwendet wegen der vagen Definition zu tun, und auch das Rohr sequence.for kann brechen StdOut offiziellen Guide
Du ven
6
@ Sieben Ich denke, Sie haben falsch verstanden; Sato sagt, dass die Verwendung von stdout unsicher ist ("sicherer Weg, die Ergebnisse unbrauchbar zu machen").
Stephen Kitt
1
Eine mögliche Standardlösung wäre, nur stderrFehlermeldungen zu melden, es sei denn, ein --verboseFlag wird verwendet, und an diesem Punkt sind auch Fortschrittsberichte enthalten.
Gaurav

Antworten:

27

Posix definiert die Standardströme somit :

Beim Programmstart müssen drei Datenströme vordefiniert und nicht explizit geöffnet werden: Standardeingabe (zum Lesen der konventionellen Eingabe), Standardausgabe (zum Schreiben der konventionellen Ausgabe) und Standardfehler (zum Schreiben der Diagnoseausgabe). Beim Öffnen ist der Standardfehlerstrom nicht vollständig gepuffert. Die Standardeingabe- und Standardausgabestreams werden nur dann vollständig gepuffert, wenn festgestellt werden kann, dass der Stream nicht auf ein interaktives Gerät verweist.

Die GNU C Library beschreibt die Standard-Streams ähnlich:

Variable: FILE * stdout
Der Standardausgabestream, der für die normale Ausgabe des Programms verwendet wird.

Variable: FILE * stderr
Der Standardfehlerstrom, der für vom Programm ausgegebene Fehlermeldungen und Diagnosen verwendet wird.

Standarddefinitionen enthalten daher nur wenige Richtlinien für die Stream-Verwendung, die über die Standard- / Normalausgabe und die Diagnose- / Fehlerausgabe hinausgehen. In der Praxis ist es üblich, einen oder beide dieser Streams auf Dateien und Pipelines umzuleiten, bei denen Fortschrittsanzeigen ein Problem darstellen . Einige Systeme überwachen sogar diestderr Ausgabe und sehen dies als Anzeichen für Probleme an. Lediglich zusätzliche Fortschrittsinformationen sind daher in beiden Streams problematisch.

Anstatt Fortschrittsanzeigen bedingungslos an einen der Standard-Streams zu senden , ist es wichtig zu erkennen, dass die Fortschrittsausgabe nur für interaktive Streams geeignet ist . Aus diesem Grund empfehle ich, Fortschrittszähler erst zu schreiben, nachdem Sie überprüft haben, ob der Stream interaktiv ist (z. B. mit isatty()) oder wenn er explizit über eine Befehlszeilenoption aktiviert wurde. Dies ist besonders wichtig für Fortschrittsanzeigen, bei denen das Aktualisierungsverhalten des Terminals sinnvoll ist, z. B.% -vollständige Balken.

Für bestimmte sehr einfache Fortschrittsmeldungen ("Starten von X" ... "Fertig mit X") ist es sinnvoller, die Ausgabe auch für nicht interaktive Streams einzuschließen. In diesem Fall sollten Sie überlegen, wie Benutzer mit den Streams interagieren können, z. B. mit suchen, mit greppagen lessoder mit überwachen tail -f. Wenn es sinnvoll ist, die Fortschrittsmeldungen in diesen Kontexten zu sehen, sind sie viel einfacher zu konsumieren stdout.

Bradd Szonye
quelle
Danke, die GNU-Richtlinie ist genau das, wonach ich strebe. Mir ist jedoch klar, dass meine Frage etwas irreführend war. Als ich "Fortschrittsberichte" erwähnte, dachte ich sowohl an Dinge wie N% doneals auch an Dinge wie doing foound foo done. Letztere sollten immer beibehalten werden, da sie beim Umleiten in eine Datei zum Debuggen verwendet werden. Ihr Vorschlag, zu überprüfen, ob der Stream interaktiv ist, ist daher nicht zutreffend (obwohl dies im Allgemeinen eine sehr gute Idee ist).
terdon
Ah, danke für die Klarstellung, das ist ein bisschen anders als nur Sachen wie „% complete“ und Hash-Mark-Fortschrittsbalken, die Sie in Software wie curlund sehen yum. In diesem Fall würde ich darüber nachdenken, ob und wie der Benutzer mit der Ausgabe über grepoder über lessähnliche Tools interagieren möchte .
Bradd Szonye
Aktualisierte Antwort, um die obigen Erläuterungen aufzunehmen.
Bradd Szonye
71

POSIX definiert Standardfehler als

zum Schreiben von Diagnoseausgaben

Dies beschränkt die Verwendung nicht nur auf Fehlermeldungen. Ich würde Fortschrittsinformationen als Diagnoseausgabe betrachten, so dass sie zu Standardfehlern gehören.

Stephen Kitt
quelle
8
FWIW ist in Python stdoutstandardmäßig zeilengepuffert, wohingegen stderres ungepuffert ist. Dies stderrist auch die natürliche Wahl für das Schreiben von Fortschritts-Text / Balken / Drehfeldern, die keine neue Zeile enthalten. (Wenn Sie einen solchen Text schreiben stdout, müssen Sie Ihre Fortschrittsaufrufe überladen stdout.flush(), um ihn sichtbar zu machen.)
PM 2Ring
12
@ PM2Ring, das nicht spezifisch für Python ist, POSIX definiert die Streams auf diese Weise.
Stephen Kitt
4
@ PM2Ring: Wenn das Schreiben stdout, müssen Sie auch spülen , wenn Ihr Text ist eine neue Zeile enthält , wenn Sie Ihre Fortschrittsberichte tatsächlich wollen in Echtzeit angezeigt, wenn umgeleitet.
@ Hurkyl Ah, guter Punkt. Ich habe keine Umleitung in Betracht gezogen.
PM 2Ring
1
@Wtower, was? Ansible schluckt stderr-Text, wenn der Beendigungsstatus 0 ist. Diese Behauptung ist einfach falsch.
Charles Duffy
10

POSIX ist etwas konkreter in Bezug auf "Diagnoseinformationen" in Shell und Dienstprogrammen , 1.4: Standardwerte für Dienstprogrammbeschreibung (Schwerpunkt Mine):

STDERR

Der Abschnitt STDERR beschreibt die Standardfehlerausgabe des Dienstprogramms. Es werden nur die Nachrichten beschrieben, die vom Dienstprogramm absichtlich gesendet werden. Die Verwendung eines Terminals für Standardfehler kann dazu führen, dass alle Standarddienstprogramme, die Standardfehler ausgeben, bei Verwendung im Hintergrund angehalten werden. Aus diesem Grund sollten Anwendungen keine interaktiven Funktionen in Skripten verwenden, um sie in den Hintergrund zu stellen.

Das Format der Diagnosemeldungen für die meisten Dienstprogramme ist nicht festgelegt, aber die sprachlichen und kulturellen Konventionen von Diagnose- und Informationsmeldungen, deren Format in dieser Ausgabe von POSIX.1-2008 nicht festgelegt ist, sollten durch die Einstellung von LC_MESSAGES und [XSI] [Option Start] beeinflusst werden ] NLSPATH. [Optionsende]

Die angegebene Standardfehlerausgabe von Standarddienstprogrammen darf nicht von der Existenz oder dem Wert der Umgebungsvariablen abhängen, die in diesem Band von POSIX.1-2008 definiert sind, es sei denn, dies wird in diesem Band von POSIX.1-2008 bereitgestellt.

Standardverhalten : Wenn dieser Abschnitt als "Der Standardfehler darf nur für Diagnosemeldungen verwendet werden." Aufgeführt ist, bedeutet dies, dass die Diagnosemeldungen , sofern nicht anders angegeben, nur dann an den Standardfehler gesendet werden, wenn der Beendigungsstatus einen Fehler anzeigt aufgetreten ist und das Dienstprogramm wie in diesem Band von POSIX.1-2008 beschrieben verwendet wird.

Wenn dieser Abschnitt als "Nicht verwendet" aufgeführt ist, bedeutet dies, dass der Standardfehler nicht verwendet werden soll, wenn das Dienstprogramm wie in diesem Band von POSIX.1-2008 beschrieben verwendet wird.

IANASL, aber ich interpretiere das so, dass stderr nur ausgegeben wird, wenn das Dienstprogramm einen Fehler-Exit-Code zurückgibt. Da dies nicht der normale Ablauf für eine erfolgreiche Ausführung sein sollte, sollten von einem POSIX-Dienstprogramm keine Fortschrittsinformationen gedruckt werden, sofern kein Fehler auftritt (sofern natürlich nichts anderes angegeben ist usw.).

muru
quelle
Ich verstehe dies als Beschreibung der Bedeutung des Abschnitts "STDERR", der in den Spezifikationen der einzelnen POSIX-Dienstprogramme angegeben ist, und nicht als allgemeine Definition für die Verwendung von Standardfehlern. Ich glaube nicht, dass terdon hier ein Standard-POSIX-Dienstprogramm schreibt ;-).
Stephen Kitt
1
@StephenKitt tut ich auch nicht. Aber er diskutiert mit seinem CTO, der sagt, dass die stderr-Ausgabe ein Hinweis darauf ist, dass etwas schief gelaufen ist, und der Standard unterstützt seine Behauptung als Standardverhalten.
Muru
1
Es wird nur die Behauptung als Standardverhalten für POSIX-Dienstprogramme unterstützt , und dies auch nur in bestimmten Fällen (Dienstprogramme, die den angegebenen Ausdruck verwenden). Dieser Teil von POSIX ist nicht normativ (AIUI), sondern eine Vorlage: Hier erfahren Sie, wie Sie die Dienstprogrammspezifikationen lesen und wie sich die Dienstprogramme verhalten. Insbesondere definiert es die Bedeutung der Sätze "Der Standardfehler darf nur für Diagnosemeldungen verwendet werden." und "Nicht verwendet." in den "STDERR" Abschnitten der Dienstprogrammspezifikationen. Jedes Dienstprogramm gibt sein Verhalten an und kann diese Ausdrücke als Kurzform verwenden.
Stephen Kitt
@StephenKitt was meinen Standpunkt nicht ändert. POSIX-Dienstprogramme werden entweder a) nicht an stderr ausgegeben, b) nur für Diagnosemeldungen verwendet, wenn etwas schief geht, c) nur für Diagnosemeldungen, auch wenn nichts schief geht, und d) für etwas anderes verwendet. Ich sagte, dass sie es nur für Diagnosemeldungen verwenden, wenn etwas schief geht (a, b), sofern nicht anders angegeben (c, d). Nun, meine Behauptung ist, dass dies die Standardeinstellung ist, die es eindeutig ist, da dies der Grund ist, warum es eine Vorlage ist.
Muru
2
Nun, ich würde sagen, das "sofern nicht anders angegeben" ist eine ziemlich bedeutende Einschränkung: Ein POSIX-Dienstprogramm könnte sehr gut angeben, dass es Fortschrittsinformationen zu seinem Standardfehler ausgibt, und es wäre standardkonform. Sie haben Recht, es ist interessant, dass das "Standardverhalten" (das immer noch eine spezielle Erwähnung im entsprechenden Abschnitt erfordert) darin besteht, Standardfehler nur dann zu verwenden, wenn der Exit-Code auch einen Fehler anzeigt. aber es ist nicht einschränkend.
Stephen Kitt
7

Nach dem Ausschlussprinzip kann es nur an stderr gehen. Ja, ich weiß, dass Sie nach einer offiziellen Spezifikation gefragt haben, die ich Ihnen nicht über den von Stephen Kitt angegebenen Link zur POSIX-Spezifikation hinaus vorstellen kann, der besagt, dass stderr für Diagnosezwecke bestimmt ist.

Der wichtigere Punkt ist, dass stdin und stdout eine Funktion haben, die das Drucken von Fortschrittsberichten für stdout nicht zulässt - sie bilden natürlich die Sequenz von Pipes, die in Unix-Shell-Befehlen nicht nur ein Nebeneffekt ist, sondern den Kern des leistungsstarken Pipelining-Ansatzes .

Damit. Auf stdout gehört nur die eigentliche "Nutzlast" Ihres Programms. Wenn Ihr Programm keine Ausgabe hat, sollte nichts auf stdout gehen. Dies lässt stderr für alles andere , einschließlich Fortschrittsberichte.

Zugegeben, dies hinterlässt eine Lücke - es wäre wahrscheinlich schön, ein "stdfluff" oder ähnliches zu haben, das weder für die Ausgabe noch für Fehler gedacht ist, sondern für Fortschrittsberichte, Debugging und ähnliches. Tatsächlich hindert Sie nichts daran, dies zu tun, dh Sie könnten Ihren Fortschritt in Dateideskriptor 3 ausgeben. Beispiel:

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

Dies erzeugt keine Ausgabe. (*)

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

Dies wird zu fd-3 gedruckt, das zu stdout umgeleitet wird.

(*) Das erste Beispiel erzeugt keine Ausgabe, ist aber noch etwas weit hergeholt. das openscheitert und $!würde enthalten no such file or directory; Nehmen Sie dies nur als Beispiel, es ist natürlich nicht ernst gemeint, so verwendet zu werden. Wenn Sie in einem tatsächlichen Programm diese Route einschlagen möchten, können Sie testen, ob /dev/fd/3es verwendbar ist, und dies als Hinweis darauf ansehen, ob Sie Ihre Fortschrittsberichte aktivieren möchten. Sie müssten das ziemlich früh tun, damit Sie nicht von Ihren eigenen opens für echte Dateien und so verwirrt werden ...

AnoE
quelle
Was ist fd-3? Die dritte Diskette?
Peter Mortensen
Dateideskriptor 3, @PeterMortensen
AnoE
-1

Die Benutzungsnachricht sollte auf stdout gehen, wenn der Benutzer sie mit aufgerufen hat, --helpund auf stderr, wenn er einen Fehler gemacht hat. Das bedingungslose Drucken auf stderr ist unangenehm, da es schwieriger ist, es mit einem Pager / grep / etc. Anzuzeigen.

Darf ich auch einen dritten Weg vorschlagen: open / dev / tty für Fortschrittsberichte / Spinner / etc.

Random832
quelle
6
Sorry, aber das beantwortet die Frage nicht. Ich habe ausdrücklich nach offiziellen Richtlinien gefragt , nicht nach einer Meinung. Auf jeden Fall beantworten Sie eine andere Frage, auch wenn ich Sie um eine Meinung gebeten habe. Ich spreche überhaupt nicht über --helpoder helfe Nachrichten. Bitte lesen Sie die Frage erneut.
terdon
Sie haben "Benutzungsnachricht" erwähnt. Ich dachte, dies ist Teil Ihrer Frage und nicht nur der Titel der anderen Frage, die Sie verlinkt haben. Ich verstehe nicht, warum es Ihrer Meinung nach "offizielle Richtlinien" dafür gibt. Wer hätte die Autorität, sie herzustellen?
Random832
3
Ich weiß nicht, dass sie es tun, deshalb frage ich. Und was das offizielle betrifft, enthält der POSIX-Standard Spezifikationen für verschiedene winzige Details, wie sich ein Programm verhalten soll. Einschließlich, wie Stephen in seiner Antwort hervorhob, eines vagen Vorschlags für das, was an stderr gehen sollte. Der GNU-Kodierungsstandard könnte auch etwas ähnliches haben. Grundsätzlich könnte jede Gruppe, die aktiv ist und Code für das * nix-Ökosystem erstellt, einen Standard haben, an dem ich interessiert sein würde.
terdon
@terdon Wäre es in Ordnung mit Beispielen, was bestehende Programme tun? curl, wget und pv verwenden alle stderr, wobei wget und pv es davon abhängig machen, dass es ein tty ist, und curl es davon abhängig machen, dass stdout nicht das tty ist.
Random832
4
Es hört sich auch so an, als ob Ihr CTO der Meinung ist, dass ein aufrufendes Programm auf das Vorhandensein von Daten auf stderr reagieren sollte, was bedeutet, dass ein Fehler aufgetreten ist, anstatt sich den Exit-Status anzusehen. Dies ist definitiv eine schlechte Übung (und auch schwieriger zu schreiben als das Überprüfen des Ausgangsstatus) und könnte ein besserer Winkel sein, um ihn davon zu überzeugen.
Random832