Os relatórios de progresso / informações de registro pertencem ao stderr ou stdout?

62

Existe um POSIX oficial, GNU ou outra diretriz sobre onde os relatórios de progresso e as informações de registro (coisas como "Fazendo foo; foo feito") devem ser impressos? Pessoalmente, tenho a tendência de escrevê-las para o stderr para que eu possa redirecionar o stdout e obter apenas a saída real do programa. Recentemente me disseram que isso não é uma boa prática, já que os relatórios de progresso não são realmente erros e somente as mensagens de erro devem ser impressas no stderr.

Ambas as posições fazem sentido, e é claro que você pode escolher uma ou outra dependendo dos detalhes do que está fazendo, mas eu gostaria de saber se existe um padrão comumente aceito para isso. Não consegui encontrar nenhuma regra específica no POSIX, nos padrões de codificação GNU ou em qualquer outra lista amplamente aceita de práticas recomendadas.

Temos algumas perguntas semelhantes, mas elas não abordam esse problema exato:

Então, existem regras oficiais sobre onde os relatórios de progresso e outras mensagens informativas (que não fazem parte da saída real do programa) devem ser impressas?

    
por terdon 20.12.2016 / 11:13

5 respostas

20

Posix define os fluxos padrão assim :

At program start-up, three streams shall be predefined and need not be opened explicitly: standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). When opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.

A Biblioteca GNU C descreve os fluxos padrão da mesma forma:

Variable: FILE * stdout
The standard output stream, which is used for normal output from the program.

Variable: FILE * stderr
The standard error stream, which is used for error messages and diagnostics issued by the program.

Portanto, as definições padrão têm pouca orientação para o uso do fluxo além da saída convencional / normal e da saída de diagnóstico / erro. Na prática, é comum redirecionar um ou ambos desses fluxos para arquivos e pipelines, onde os indicadores de progresso ser um problema. Alguns sistemas até mesmo monitoram stderr para saída e consideram um sinal de problemas. Informações de progresso puramente auxiliares são, portanto, problemáticas em qualquer fluxo.

Em vez de enviar indicadores de progresso incondicionalmente para qualquer fluxo padrão, é importante reconhecer que a saída de progresso é apropriada apenas para fluxos interativos . Com isso em mente, recomendo escrever contadores de progresso somente depois de verificar se o fluxo é interativo (por exemplo, com isatty() ) ou quando explicitamente habilitado por uma opção de linha de comando. Isso é especialmente importante para os medidores de progresso que dependem do comportamento da atualização de terminal para fazer sentido, como barras de% -completa.

Para determinadas mensagens de progresso muito simples ("Iniciando X" ... "Concluído com X"), é mais razoável incluir a saída mesmo para fluxos não interativos. Nesse caso, considere como os usuários podem interagir com os fluxos, como pesquisar com grep ou paginar com less ou monitorar com tail -f . Se fizer sentido ver as mensagens de progresso nesses contextos, será muito mais fácil consumir de stdout .

    
por 21.12.2016 / 03:28
67

POSIX define o erro padrão como

for writing diagnostic output

Isso não limita seu uso apenas a mensagens de erro. Eu consideraria a informação de progresso como saída de diagnóstico, então ela pertence ao erro padrão.

    
por 20.12.2016 / 11:35
9

POSIX é um pouco mais concreto sobre "informações de diagnóstico" em Shell e utilitários 1.4: Utilitário Descrição Padrões (grifo meu):

STDERR

The STDERR section describes the standard error output of the utility. Only those messages that are purposely sent by the utility are described. Use of a terminal for standard error may cause any of the standard utilities that write standard error output to stop when used in the background. For this reason, applications should not use interactive features in scripts to be placed in the background.

The format of diagnostic messages for most utilities is unspecified, but the language and cultural conventions of diagnostic and informative messages whose format is unspecified by this volume of POSIX.1-2008 should be affected by the setting of LC_MESSAGES and [XSI] [Option Start] NLSPATH. [Option End]

The specified standard error output of standard utilities shall not depend on the existence or value of the environment variables defined in this volume of POSIX.1-2008, except as provided by this volume of POSIX.1-2008.

Default Behavior: When this section is listed as "The standard error shall be used only for diagnostic messages.", it means that, unless otherwise stated, the diagnostic messages shall be sent to the standard error only when the exit status indicates that an error occurred and the utility is used as described by this volume of POSIX.1-2008.

When this section is listed as "Not used.", it means that the standard error shall not be used when the utility is used as described in this volume of POSIX.1-2008.

IANASL, mas interpreto isso como significando que stderr terá saída somente se o utilitário retornar um código de saída de erro. Como esse não deve ser o curso normal dos eventos para uma execução bem-sucedida, nenhuma informação de progresso deve ser impressa por um utilitário POSIX, a menos que ocorra um erro (a menos que seja especificado, etc.). p>     

por 21.12.2016 / 07:51
6

Pelo princípio da exclusão, só pode ir para stderr. Sim, eu sei que você perguntou sobre uma especificação oficial, que não posso apresentá-lo além do link para a especificação POSIX, dada por Stephen Kitt, que afirma que stderr é para fins de diagnóstico.

O ponto mais importante é que stdin e stdout têm uma função que proíbe a impressão de relatórios de progresso para stdout - eles formam a sequência de pipes que em comandos de shell Unix não é apenas um efeito colateral, mas o próprio núcleo do comando abordagem poderosa de pipelining.

Nada, exceto o verdadeiro "payload" do seu programa pertence ao stdout. Se o seu programa não tem saída, então nada deve ir para stdout. Isso deixa stderr para todo o resto , incluindo relatórios de progresso.

Concedido, isso deixa um buraco - provavelmente seria bom ter um "stdfluff" ou algo parecido, que não é para nem saída nem erros, mas relatórios de progresso, depuração e algo assim. Na verdade, nada impede que você faça isso, ou seja, você pode imprimir seu progresso para o descritor de arquivo 3. Exemplo:

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

Isso não produz saída. (*)

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

Isto imprime em fd-3, que é redirecionado para stdout.

(*) O primeiro exemplo não produz saída, mas ainda é um pouco exagerado; o open falha e $! conteria no such file or directory ; apenas tome isso como um exemplo, é claro que não é para ser usado assim a sério. Em um programa real, se você quiser seguir esse caminho, você pode testar se /dev/fd/3 é utilizável e tomar isso como uma sugestão de ativar seus relatórios de progresso; você teria que fazer isso bem cedo para não ficar confuso com o seu próprio open s para arquivos reais e tal ...

    
por 21.12.2016 / 00:47
-2

A mensagem de uso deve ir para stdout se o usuário a invocar com --help e para stderr se tiver cometido um erro. Imprimi-lo para o stderr incondicionalmente é desagradável porque torna mais difícil visualizá-lo com um pager / grep / etc.

Além disso, sugiro uma terceira via: abrir / dev / tty para relatórios de progresso / spinners / etc.

    
por 20.12.2016 / 16:03