I rapporti sui progressi / le informazioni di registrazione appartengono a stderr o stdout?


75

Esiste un POSIX ufficiale, GNU o altre linee guida su dove dovrebbero essere stampate le relazioni sui progressi e le informazioni di registrazione (cose come "Fare foo; foo done")? Personalmente, tendo a scriverli su stderr in modo da poter reindirizzare stdout e ottenere solo l'output effettivo del programma. Recentemente mi è stato detto che questa non è una buona pratica poiché i rapporti sui progressi non sono in realtà errori e solo i messaggi di errore dovrebbero essere stampati su stderr.

Entrambe le posizioni hanno un senso, e ovviamente puoi scegliere l'una o l'altra a seconda dei dettagli di ciò che stai facendo, ma vorrei sapere se esiste uno standard comunemente accettato per questo. Non sono stato in grado di trovare regole specifiche in POSIX, negli standard di codifica GNU o in qualsiasi altro elenco di best practice ampiamente accettato.

Abbiamo alcune domande simili, ma non affrontano questo problema esatto:

Quindi, ci sono delle regole ufficiali su dove dovrebbero essere stampati rapporti sullo stato di avanzamento e altri messaggi informativi (che non fanno parte dell'output effettivo del programma)?


26
La stampa di filatori e simili stdoutinsieme ai risultati è un modo sicuro per rendere inutili i risultati. Se hai mai bisogno di convogliare i risultati ad un altro programma, detto programma dovrebbe separare i risultati dagli spinner. Inoltre, se reindirizzi l'output su un file non sarai in grado di vedere i filatori. A PARER MIO.
Satō Katsura,

2
@SatoKatsura sì, anche questa è la mia opinione ed è per questo che stampo su Stderr. Il CTO della società per cui lavoro, tuttavia, ritiene che la stampa su stderr sia un'indicazione che qualcosa è andato storto. Ho affermato, piuttosto audace, che POSIX Way® sta stampando su stderr e mi ha chiamato per questo. Dato che ha 20 anni dispari di esperienza su di me, vorrei vedere se riesco a trovare una sorta di linea guida "ufficiale".
terdon

come ha detto Sato Katsura, stdoutè in realtà un modo sicuro e giusto per spingere i filatori e altri messaggi informativi, ma come molti programmatori dicono "Il silenzio è d'oro. Non produrre nulla se tutto va bene. ' quindi, in effetti, stderr è sempre usato per farlo a causa della definizione vaga e anche stdout potrebbe interrompere la sequenza di tubi. per guida ufficiale
Se ven

6
@Seven Penso che tu abbia frainteso; Sato sta dicendo che l'uso di stdout non è sicuro ("un modo sicuro per rendere inutili i risultati").
Stephen Kitt,

1
Una possibile soluzione unica per tutti sarebbe quella di utilizzare solo stderrper segnalare messaggi di errore, tranne quando --verboseviene utilizzato un flag, a quel punto vengono inclusi anche i rapporti sullo stato di avanzamento.
Gaurav,

Risposte:


27

Posix definisce quindi i flussi standard :

All'avvio del programma, tre flussi devono essere predefiniti e non devono essere aperti in modo esplicito: input standard (per leggere input convenzionali), output standard (per scrivere output convenzionali) ed errore standard (per scrivere output diagnostici). Se aperto, il flusso di errori standard non è completamente bufferizzato; i flussi di input standard e output standard sono completamente bufferizzati se e solo se il flusso può essere determinato in modo da non fare riferimento a un dispositivo interattivo.

La libreria GNU C descrive i flussi standard in modo simile:

Variabile: FILE * stdout
Il flusso di output standard, utilizzato per l'output normale dal programma.

Variabile: FILE * stderr
Il flusso di errore standard, utilizzato per i messaggi di errore e la diagnostica emessi dal programma.

Pertanto, le definizioni standard hanno poche indicazioni per l'utilizzo del flusso oltre "output convenzionale / normale" e "output diagnostico / di errore". In pratica, è comune reindirizzare uno o entrambi questi flussi su file e pipeline, in cui gli indicatori di progresso saranno un problema . Alcuni sistemi monitorano persino l' stderroutput e lo considerano un segnale di problemi. Le informazioni sull'avanzamento puramente ausiliario sono quindi problematiche su entrambi i flussi.

Invece di inviare gli indicatori di progresso incondizionatamente a uno dei flussi standard, è importante riconoscere che l'output dei progressi è appropriato solo per i flussi interattivi . Con questo in mente, raccomando di scrivere contatori di avanzamento solo dopo aver verificato se il flusso è interattivo (ad es. Con isatty()) o se esplicitamente abilitato da un'opzione della riga di comando. Ciò è particolarmente importante per i misuratori di progresso che si basano sul comportamento di aggiornamento dei terminali per avere un senso, come le barre complete di%.

Per alcuni messaggi di avanzamento molto semplici ("Avvio di X" ... "Fine con X") è più ragionevole includere l'output anche per i flussi non interattivi. In tal caso, considera in che modo gli utenti potrebbero interagire con gli stream, come cercare grepo effettuare il paging lesso il monitoraggio con tail -f. Se ha senso vedere i messaggi di avanzamento in quei contesti, saranno molto più facili da consumare stdout.


Grazie, la linea guida GNU è il genere di cosa che sto cercando. Tuttavia, mi rendo conto che la mia domanda era un po 'fuorviante. Quando ho citato "relazioni sullo stato di avanzamento", stavo pensando a cose come N% donee cose come doing fooe foo done. Questi ultimi devono sempre essere conservati poiché vengono utilizzati per il debug quando vengono reindirizzati a un file. Quindi il tuo suggerimento di verificare se lo stream è interattivo non è applicabile (anche se generalmente è un'ottima idea).
terdon

Ah grazie per il chiarimento, è un po 'diverso da cose come “% complete” e barre di avanzamento con segno di hash che vedi in software come curle yum. In tal caso, penserei a se e come l'utente vorrebbe interagire con l'output tramite grepo lesso strumenti simili.
Bradd Szonye,

Risposta aggiornata per incorporare chiarimenti sopra.
Bradd Szonye,

71

POSIX definisce l'errore standard come

per scrivere output diagnostico

Ciò non limita il suo utilizzo solo ai messaggi di errore. Considererei le informazioni sui progressi come output diagnostici, quindi appartengono a errori standard.


8
FWIW, in Python, stdoutè bufferizzato in linea per impostazione predefinita, mentre stderrnon è bufferizzato, quindi stderrè la scelta naturale per la scrittura di testo / barre / spinner di avanzamento che non contengono una nuova riga. (Se scrivi tale testo su di esso stdoutdevi ingombrare le tue chiamate di output dei progressi con stdout.flush()per renderlo visibile).
PM 2Ring

12
@ PM2Ring non specifico di Python, POSIX definisce i flussi in questo modo.
Stephen Kitt,

4
@ PM2Ring: Quando si scrive a stdout, è necessario svuotare anche se il testo non contiene un ritorno a capo, se si desidera che le relazioni di avanzamento per mostrare realmente in tempo reale quando reindirizzato.

@Hurkyl Ah, buon punto. Non stavo considerando il reindirizzamento.
PM 2Ring

1
@Wtower, eh? No. Ansible ingoia il testo standard se lo stato di uscita è 0. Tale affermazione è semplicemente falsa.
Charles Duffy,

10

POSIX è leggermente più concreto riguardo alle "informazioni diagnostiche" in Shell e Utilità , 1.4: Default Descrizione Utilità (enfasi):

STDERR

La sezione STDERR descrive l'output di errore standard dell'utilità. Vengono descritti solo i messaggi inviati di proposito dall'utilità. L'uso di un terminale per errore standard può causare l'interruzione di qualsiasi utilità standard che scrive l'output di errore standard quando utilizzato in background. Per questo motivo, le applicazioni non devono utilizzare funzionalità interattive negli script per essere posizionate in background.

Il formato dei messaggi diagnostici per la maggior parte delle utility non è specificato, ma le convenzioni linguistiche e culturali dei messaggi diagnostici e informativi il cui formato non è specificato da questo volume di POSIX.1-2008 dovrebbero essere influenzate dall'impostazione di LC_MESSAGES e [XSI] [Opzione Avvio ] NLSPATH. [Fine opzione]

L'output di errore standard specificato delle utility standard non dipende dall'esistenza o dal valore delle variabili di ambiente definite in questo volume di POSIX.1-2008, ad eccezione di quanto previsto da questo volume di POSIX.1-2008.

Comportamento predefinito : quando questa sezione è elencata come "L'errore standard deve essere utilizzato solo per i messaggi diagnostici", significa che, se non diversamente indicato, i messaggi diagnostici devono essere inviati all'errore standard solo quando lo stato di uscita indica che un errore si è verificato e l'utilità viene utilizzata come descritto da questo volume di POSIX.1-2008.

Quando questa sezione è elencata come "Non utilizzato", significa che l'errore standard non deve essere utilizzato quando si utilizza l'utilità come descritto in questo volume di POSIX.1-2008.

IANASL, ma interpreto ciò per indicare che stderr avrà un output solo se l'utility restituirà un codice di uscita dell'errore. Dal momento che questo non dovrebbe essere il normale corso degli eventi per un'esecuzione corretta, nessuna informazione sull'avanzamento dovrebbe essere stampata da un'utilità POSIX a meno che non si verifichi un errore (a meno che, ovviamente, diversamente specificato, ecc.).


Lo capisco come descrivendo il significato della sezione "STDERR" fornita nelle specifiche di ciascuna utility POSIX, non come una definizione generale per l'utilizzo di errori standard. Non credo che Terdon stia scrivendo un'utilità POSIX standard qui ;-).
Stephen Kitt,

1
@StephenKitt nemmeno io. Ma sta discutendo con il suo CTO, il quale afferma che l'output di stderr è un'indicazione di qualcosa che non va, e lo standard supporta la sua affermazione come comportamento predefinito.
Muru,

1
Supporta solo l'affermazione come comportamento predefinito per le utility POSIX e anche solo in casi specifici (utility che usano la frase menzionata). Questa parte di POSIX non è normativa (AIUI), è un modello: ti dice come leggere le specifiche delle utility, non specifica il comportamento delle utility. In particolare, definisce i significati delle frasi "L'errore standard deve essere utilizzato solo per i messaggi diagnostici". e "Non utilizzato". nelle sezioni "STDERR" delle specifiche di utilità. Ogni utility specifica il suo comportamento e può usare quelle frasi come stenografia.
Stephen Kitt,

@StephenKitt che non cambia il mio punto. I programmi di utilità POSIX a) non vengono inviati a stderr, b) usalo solo per messaggi diagnostici se qualcosa va storto, c) usalo solo per messaggi diagnostici anche se nulla va storto e d) usalo per qualcos'altro. Ho detto che lo usano solo per messaggi diagnostici se qualcosa va storto (a, b), se non diversamente indicato (c, d). Ora, la mia affermazione è che questo è il valore predefinito, che è chiaramente, dal momento che è il modello.
Muru,

2
Bene, direi che "se non diversamente specificato" è un avvertimento piuttosto significativo: un'utilità POSIX potrebbe benissimo specificare che produce informazioni sull'avanzamento sul suo errore standard e sarebbe conforme agli standard. Hai ragione, è interessante notare che il "comportamento predefinito" (che richiede ancora una menzione specifica nella sezione pertinente) consiste nell'utilizzare l'errore standard solo se il codice di uscita indica anche un errore; ma non è limitante.
Stephen Kitt,

7

Secondo il principio di esclusione, può solo andare a stderr. Sì, so che hai chiesto informazioni su una specifica ufficiale, che non posso presentarti oltre il collegamento alla specifica POSIX, data da Stephen Kitt, che afferma che stderr è a fini diagnostici.

Il punto più importante è che stdin e stdout hanno una funzione che non consente di stampare report di avanzamento su stdout - ovviamente formano la sequenza di pipe che nei comandi della shell Unix non è solo un effetto collaterale, ma il nucleo stesso del potente approccio di pipelining .

Così. Nulla, tranne il vero "payload" del tuo programma, appartiene a stdout. Se il tuo programma non ha output, allora nulla dovrebbe andare su stdout. Questo lascia stderr per tutto il resto , compresi i rapporti sui progressi.

Certo, questo lascia un buco - sarebbe probabilmente bello avere uno "stdfluff" o qualcosa del genere che non è né per output né per errori, ma per i rapporti sui progressi, il debugging e altro. In realtà, nulla ti impedisce di farlo, ad esempio, potresti stampare i tuoi progressi sul descrittore di file 3. Esempio:

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

Questo non produce output. (*)

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

Questo stampa su fd-3, che viene reindirizzato su stdout.

(*) Il primo esempio non produce output ma è ancora un po 'inverosimile; i openfallimenti e $!conterrebbero no such file or directory; prendi questo come esempio, ovviamente non è un modo di essere usato in questo modo sul serio. In un programma reale, se si desidera seguire questa strada, è possibile verificare se /dev/fd/3è utilizzabile e prendere questo come suggerimento per l'attivazione dei rapporti sui progressi compiuti; dovresti farlo abbastanza presto in modo da non confonderti con i tuoi openfile reali e simili ...


Che cosa è fd-3? Il terzo floppy disk?
Peter Mortensen,

descrittore di file 3, @PeterMortensen
AnoE

-1

Il messaggio di utilizzo dovrebbe andare su stdout se l'utente lo ha invocato --helpe su stderr se ha commesso un errore. Stamparlo su stderr incondizionatamente è odioso perché rende più difficile visualizzarlo con un cercapersone / grep / etc.

Inoltre, posso suggerire una terza via: open / dev / tty per i report sui progressi / spinner / ecc.


6
Siamo spiacenti, ma questo non risponde alla domanda. Ho specificamente chiesto linee guida ufficiali , non opinioni. In ogni caso, anche se avessi chiesto un parere, stai rispondendo a una domanda diversa. Non sto parlando --helpo aiuto ai messaggi. Rileggi la domanda.
terdon

Hai citato "messaggio di utilizzo", pensavo fosse parte della tua domanda piuttosto che solo il titolo dell'altra domanda che hai collegato. Non capisco perché pensi che esistano "linee guida ufficiali" per questo. Chi avrebbe l'autorità per realizzarli?
Casuale 832

3
Non so che lo fanno, ecco perché lo chiedo. E per quanto riguarda il funzionario, lo standard POSIX ha specifiche per vari minuti dettagliati su come dovrebbe comportarsi un programma. Compreso, come ha sottolineato Stephen nella sua risposta, un vago suggerimento per cosa dovrebbe andare a Stderr. Lo standard di codifica GNU potrebbe anche avere qualcosa di simile. Fondamentalmente, qualsiasi gruppo che è attivo e produce codice per l'ecosistema * nix potrebbe avere uno standard a cui sarei interessato.
terdon

@terdon staresti bene con esempi di cosa fanno i programmi esistenti? curl, wget e pv usano tutti stderr, con wget e pv che lo rendono condizionato dal fatto che è un tty e curl che lo rende condizionato dal fatto che stdout non sia il tty.
Casuale 832

4
Inoltre, sembra che il tuo CTO pensi che un programma chiamante dovrebbe reagire alla presenza di dati su stderr nel senso che si è verificato un errore, piuttosto che guardare lo stato di uscita. Questa è sicuramente una cattiva pratica (e anche più difficile da scrivere rispetto al controllo dello stato di uscita) e potrebbe essere un angolo migliore per convincerlo.
Casuale 832
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.