Confuso sobre stdin, stdout e stderr?

230

Estou um pouco confuso com o objetivo desses três arquivos. Se meu entendimento estiver correto, stdiné o arquivo no qual um programa grava suas solicitações para executar uma tarefa no processo, stdouté o arquivo no qual o kernel grava sua saída e o processo que solicita o acesso às informações e stderré o arquivo em em que todas as exceções são inseridas. Ao abrir esses arquivos para verificar se eles realmente ocorrem, não achei nada que sugerisse isso!

O que eu gostaria de saber é qual é exatamente o objetivo desses arquivos, resposta absolutamente estúpida com muito pouco jargão técnico!

Shouvik
fonte
36
Observação: essa pergunta era aceitável em 2010, mas seria votada muito rapidamente hoje em dia.
byxor
3
@Brandon Você pode fornecer um motivo? Eu acho que seria valioso para o seu comentário.
Independent
3
@ Byxor para ser justo, vou perguntar: O post do op estava pedindo para o pessoal ajudá-lo a depurar seu código? parece que Shouvik fez uma pergunta sobre o propósito de stdin, stdout e stderr. o post do op parece ser curioso, não? (Na verdade, estou aprendendo sobre isso mesmo atm graças, SO, por não remover este post.)
sansae
2
@ user123456 você está correto. Eu estava aprendendo a ser desenvolvedor de software e a S / O naquela época era um ótimo lugar para aprender sobre programação. Originalmente, pretendíamos que fosse um serviço wiki para todas as perguntas sobre ciências da computação. #juniorDevForLife
Shouvik
3
@Shouvik, obrigado por esse pouco de história. Estou aprendendo a ser desenvolvedor de software também (acabei de ser aceito em um acampamento legal na sf). Ainda sou relativamente novo em S / O e ainda não tenho certeza sobre o que posso ou não publicar. Acho que a moderação aqui pode ser bastante rigorosa. Eu gosto dessa tag de hash. #juniorDevForLife. Eu gostaria de receber você em vez de comentar aqui, pois isso não acrescenta nada à discussão, mas não acredito que S / O tenha um sistema de pm. Tenha um ótimo dia.
sansae

Respostas:

251

Entrada padrão - este é o identificador de arquivo que seu processo lê para obter informações de você.

Saída padrão - seu processo grava informações normais neste identificador de arquivo.

Erro padrão - seu processo grava informações de erro neste identificador de arquivo.

Isso é o mais estúpido que eu consigo :-)

Claro, isso é principalmente por convenção. Não há nada que o impeça de gravar suas informações de erro na saída padrão, se desejar. Você pode até fechar totalmente os três identificadores de arquivo e abrir seus próprios arquivos para E / S.

Quando o processo é iniciado, ele já deve ter esses identificadores abertos e pode apenas ler e / ou gravar neles.

Por padrão, eles provavelmente estão conectados ao seu dispositivo de terminal (por exemplo, /dev/tty) , mas os shells permitem que você configure conexões entre esses identificadores e arquivos e / ou dispositivos específicos (ou até pipelines para outros processos) antes do início do processo (alguns dos as manipulações possíveis são bastante inteligentes).

Um exemplo sendo:

my_prog <inputfile 2>errorfile | grep XYZ

que irá:

  • criar um processo para my_prog.
  • abra inputfilecomo sua entrada padrão (identificador de arquivo 0).
  • abra errorfilecomo seu erro padrão (identificador de arquivo 2).
  • crie outro processo para grep.
  • anexe a saída padrão de my_progà entrada padrão de grep.

Re seu comentário:

Quando abro esses arquivos na pasta / dev, como é que eu nunca consigo ver a saída de um processo em execução?

É porque eles não são arquivos normais. Embora o UNIX apresente tudo como um arquivo em um sistema de arquivos em algum lugar, isso não ocorre nos níveis mais baixos. A maioria dos arquivos na /devhierarquia são dispositivos de caracteres ou de bloco, efetivamente um driver de dispositivo. Eles não têm um tamanho, mas têm um número de dispositivo maior e menor.

Quando você os abre, você está conectado ao driver de dispositivo, e não a um arquivo físico, e o driver de dispositivo é inteligente o suficiente para saber que processos separados devem ser tratados separadamente.

O mesmo vale para o sistema de /procarquivos Linux . Esses não são arquivos reais, apenas gateways fortemente controlados para obter informações do kernel.

paxdiablo
fonte
1
Isso é a sua resposta. Embora eu possa entender o objetivo dos arquivos pelo que você descreve, eu gostaria de mudar um nível mais. quando abro esses arquivos na pasta / dev, como é que eu nunca consigo ver a saída de um processo em execução. Digamos que eu executo o topo do terminal, não deve produzir seus resultados no arquivo stdout periodicamente; portanto, quando estiver sendo atualizado, eu poderei ver uma instância da saída sendo impressa nesse arquivo. Mas não é assim. Esses arquivos também não são os mesmos (aqueles no diretório / dev).
Shouvik 02/08/10
7
Porque esses não são tecnicamente arquivos. Eles são nós de dispositivo, indicando um dispositivo específico no qual gravar. O UNIX pode apresentar tudo a você como uma abstração de arquivo, mas isso não acontece nos níveis mais profundos.
22410
1
Use o recurso de redirecionamento de shell. xyz >xyz.outgravará sua saída padrão em um arquivo físico que pode ser lido por outros processos. xyz | grep somethingconectará o xyzstdout ao grepstdin mais diretamente. Se você deseja acesso irrestrito a um processo que não controla dessa maneira, precisará procurar algo como /procou escrever um código para filtrar a saída conectando o kernel de alguma forma. Pode haver outras soluções, mas todas elas provavelmente são tão perigosas quanto as outras :-) #
384
20
@Shouvik, observe que /dev/stdiné um link simbólico para /proc/self/fd/0- o primeiro descritor de arquivo aberto pelo programa em execução no momento. Portanto, o que é indicado por /dev/stdinmudará de programa para programa, porque /proc/self/sempre aponta para o 'programa em execução'. (Qualquer que seja o programa que está fazendo a openligação.) /dev/stdinE os amigos foram colocados lá para tornar os scripts do shell setuid mais seguros e permitem que você passe o nome do arquivo /dev/stdinpara programas que funcionam apenas com arquivos, mas que você deseja controlar de maneira mais interativa. (Algum dia isso vai ser um truque útil para você conhecer :).
sarnold
1
@ CarlosW.Mercado, um arquivo é uma manifestação física dos dados. Por exemplo, os bits armazenados no disco rígido. Um identificador de arquivo é (geralmente) um pequeno token usado para se referir a esse arquivo, depois que você o abre.
21418
62

Seria mais correto dizer que stdin, stdoute stderrsão "fluxos de E / S" em vez de arquivos. Como você notou, essas entidades não vivem no sistema de arquivos. Mas a filosofia do Unix, no que diz respeito à E / S, é "tudo é um arquivo". Na prática, isso realmente significa que você pode usar as mesmas funções de biblioteca e interfaces ( printf, scanf, read, write, select, etc.) sem se preocupar se o fluxo de I / O é conectado a um teclado, um arquivo em disco, uma tomada, um tubo, ou alguma outra abstração de E / S.

A maioria dos programas precisa ler entrada, saída de gravação, e erros de registro, por isso stdin, stdoute stderrsão predefinidos para você, como uma conveniência de programação. Esta é apenas uma convenção e não é aplicada pelo sistema operacional.

Jim Lewis
fonte
Obrigado por suas contribuições. Você saberia como eu poderia interceptar o fluxo de dados de saída de um processo e enviá-lo para um arquivo próprio?
Shouvik 02/08/10
51

Como complemento das respostas acima, segue um resumo sobre os redirecionamentos: Cheatsheet de redirecionamentos

EDIT: Este gráfico não está totalmente correto, mas não sei por que ...

O gráfico diz que 2> & 1 tem o mesmo efeito que &> no entanto

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>
Leopold Gault
fonte
4
Seu comentário combinado com a resposta aceita faz todo o sentido e explica claramente as coisas! Obrigado!
Mykola 12/06
1
Uma imagem vale mais que mil palavras !
tauseef_CuriousGuy
22

Receio que sua compreensão seja completamente invertida. :)

Pense em "entrada padrão", "saída padrão" e "erro padrão" da perspectiva do programa , não da perspectiva do kernel.

Quando um programa precisa imprimir a saída, normalmente imprime na "saída padrão". Normalmente, um programa imprime a saída na saída padrão printf, que imprime SOMENTE na saída padrão.

Quando um programa precisa imprimir informações de erro (não necessariamente exceções, essas são uma construção da linguagem de programação, imposta em um nível muito mais alto), normalmente é impresso como "erro padrão". Normalmente, faz isso com fprintf, que aceita um fluxo de arquivos para usar na impressão. O fluxo de arquivos pode ser qualquer arquivo aberto para gravação: saída padrão, erro padrão ou qualquer outro arquivo que tenha sido aberto com fopenou fdopen.

"entrada padrão" é usado quando o arquivo precisa ler a entrada, usando freadou fgets, ou getchar.

Qualquer um desses arquivos pode ser facilmente redirecionado do shell, assim:

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 toda a enchilada:

cat < /etc/passwd > /tmp/out 2> /tmp/err

Há duas advertências importantes: primeiro, "entrada padrão", "saída padrão" e "erro padrão" são apenas uma convenção. Eles são uma convenção muito forte , mas é apenas um acordo que é muito bom poder executar programas como este: grep echo /etc/services | awk '{print $2;}' | sorte ter as saídas padrão de cada programa conectadas à entrada padrão do próximo programa no pipeline.

Segundo, forneci as funções ISO C padrão para trabalhar com fluxos de arquivos ( FILE *objetos) - no nível do kernel, são todos os descritores de arquivos ( intreferências à tabela de arquivos) e operações de nível muito inferior, como reade write, que não são faça o buffer feliz das funções ISO C. Eu pensei em simplificar e usar as funções mais fáceis, mas pensei que você deveria conhecer as alternativas. :)

sarnold
fonte
Assim, quando o processo está sendo executado, ele grava erros nesse arquivo stderr ou quando o programa está sendo compilado a partir de sua origem. Além disso, quando falamos sobre esses arquivos da perspectiva do compilador, é diferente do que quando comparado com, digamos, um programa?
Shouvik 02/08/10
1
@Shouvik, o compilador é apenas outro programa, com seu próprio stdin, stdout e stderr. Quando o compilador precisar escrever avisos ou erros, ele será gravado no stderr. Quando o front-end do compilador gera código intermediário para o assembler, ele pode escrever o código intermediário no stdout e o assembler pode aceitar sua entrada no stdin, mas tudo isso estaria nos bastidores da sua perspectiva de usuário.) Depois de ter um programa compilado, esse programa também pode gravar erros em seu erro padrão, mas não tem nada a ver com a compilação.
sarnold
Obrigado por esse token de informação. Eu acho que é muito estúpido da minha parte não vê-lo nessa perspectiva de qualquer maneira ...: P
Shouvik
1
Então você está dizendo que a norma nos ajuda a imprimir o programa
babygame0ver
9

stdin

Lê a entrada através do console (por exemplo, entrada do teclado). Usado em C com scanf

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

stdout

Produz saída para o console. Usado em C com printf

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

stderr

Produz saída de 'erro' para o console. Usado em C com fprintf

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

Redirecionamento

A fonte do stdin pode ser redirecionada. Por exemplo, em vez de vir da entrada do teclado, ela pode vir de um arquivo ( echo < file.txt) ou de outro programa ( ps | grep <userid>).

Os destinos para stdout, stderr também podem ser redirecionados. Por exemplo, stdout pode ser redirecionado para um arquivo: ls . > ls-output.txtnesse caso, a saída é gravada no arquivo ls-output.txt. Stderr pode ser redirecionado com 2>.

mikek3332002
fonte
8

Acho que as pessoas que dizem que stderrdevem ser usadas apenas para mensagens de erro são enganosas.

Também deve ser usado para mensagens informativas destinadas ao usuário que está executando o comando e não a possíveis consumidores a jusante dos dados (por exemplo, se você executa um pipe de shell encadeando vários comandos, não deseja mensagens informativas como "obter o item 30 de 42424 "para aparecer, stdoutpois eles confundirão o consumidor, mas você ainda pode querer que o usuário os veja.

Veja isto para a lógica histórica:

"Todos os programas colocavam diagnósticos na saída padrão. Isso sempre causava problemas quando a saída era redirecionada para um arquivo, mas tornava-se intolerável quando a saída era enviada para um processo desavisado. No entanto, não estava disposto a violar a simplicidade da entrada padrão. modelo de saída padrão, as pessoas toleraram esse estado de coisas através da versão 6. Logo depois, Dennis Ritchie cortou o nó górdio, introduzindo o arquivo de erro padrão. Isso não foi suficiente. Com os pipelines, o diagnóstico pode vir de qualquer um dos vários programas em execução simultaneamente. para se identificar ".

dee
fonte
3

O uso do ps -aux revela os processos atuais, todos listados em / proc / as / proc / (pid) /, chamando cat / proc / (pid) / fd / 0 e imprime qualquer coisa encontrada na saída padrão do esse processo eu acho. Então talvez,

/ proc / (pid) / fd / 0 - Arquivo de saída padrão
/ proc / (pid) / fd / 1 - Arquivo de entrada padrão
/ proc / (pid) / fd / 2 - Arquivo de erro padrão

por exemplominha janela do terminal

Mas isso só funcionou bem para / bin / bash outros processos geralmente não tinham nada em 0, mas muitos tinham erros escritos em 2

Sam
fonte
3

Para obter informações oficiais sobre esses arquivos, consulte as páginas do manual, execute o comando no seu terminal.

$ man stdout 

Mas, para uma resposta simples, cada arquivo é para:

stdout para um fluxo de saída

stdin para uma entrada de fluxo

stderr para erros de impressão ou mensagens de log.

Cada programa unix possui cada um desses fluxos.

Margach Chris
fonte
2

O stderr não executará o buffer do IO Cache; portanto, se nosso aplicativo precisar imprimir informações críticas de mensagens (alguns erros, exceções) no console ou no arquivo, use-o onde antes de escrever nossas mensagens no arquivo, o aplicativo pode fechar, deixando a depuração complexa

geekanil
fonte
0

Um arquivo com buffer associado é chamado de fluxo e é declarado como um ponteiro para um tipo definido FILE. A função fopen () cria certos dados descritivos para um fluxo e retorna um ponteiro para designar o fluxo em todas as transações adicionais. Normalmente, existem três fluxos abertos com ponteiros constantes declarados no cabeçalho e associados aos arquivos abertos padrão. Na inicialização do programa, três fluxos são predefinidos e não precisam ser abertos explicitamente: entrada padrão (para leitura de entrada convencional), saída padrão (para gravação de saída convencional) e erro padrão (para gravação de saída de diagnóstico). Quando aberto, o fluxo de erro padrão não é totalmente armazenado em buffer; os fluxos de entrada e saída padrão são totalmente armazenados em buffer se, e somente se, o fluxo puder ser determinado para não se referir a um dispositivo interativo

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

Bahruz Balabayov
fonte