Confuso su stdin, stdout e stderr?


230

Sono piuttosto confuso con lo scopo di questi tre file. Se la mia comprensione è corretta, stdinè il file in cui un programma scrive nelle sue richieste per eseguire un'attività nel processo, stdoutè il file in cui il kernel scrive il suo output e il processo che lo richiede accede alle informazioni da, ed stderrè il file in in cui sono inserite tutte le eccezioni. All'apertura di questi file per verificare se si verificano effettivamente, non ho trovato nulla che suggerisca così!

Quello che vorrei sapere è qual è esattamente lo scopo di questi file, risposta assolutamente stupida con un gergo tecnologico molto piccolo!


36
Osservazione: questa domanda era accettabile nel 2010, ma oggi verrebbe ridimensionata molto rapidamente.
byxor,

3
@Brandon Puoi fornire un motivo? Penso che sarebbe prezioso per il tuo commento.
Indipendente il

3
@byxor per essere onesti, chiederò: il post di op chiedeva alle persone di aiutarlo a eseguire il debug del suo codice? sembra che Shouvik abbia posto una domanda riguardo allo scopo di stdin, stdout e stderr. il post dell'op sembra essere per curiosità, no? (Sto davvero imparando a conoscere me stesso, grazie. SO, per non aver rimosso questo post)
sansae,

2
@ user123456 hai ragione. Stavo imparando a essere uno sviluppatore di software e S / O allora era un ottimo posto per conoscere la programmazione. Inizialmente intendevamo che fosse un servizio wiki di sorta per tutte le domande sulle scienze informatiche. #juniorDevForLife
Shouvik

3
@Shouvik grazie per quel po 'di storia. Sto imparando anche a essere uno sviluppatore di software (appena accettato in un bel campo in sf). Sono ancora abbastanza nuovo in S / O e ancora incerto su ciò che posso e non posso pubblicare. Trovo che la moderazione qui possa essere piuttosto severa. Mi piace quel tag hash. #juniorDevForLife. Vorrei pm invece di commentare qui poiché questo non aggiunge nulla alla discussione, ma non credo che S / O abbia un sistema pm. Vi auguro una buona giornata.
sansae,

Risposte:


251

Input standard : questo è il handle di file che il tuo processo legge per ottenere informazioni da te.

Uscita standard : il processo scrive informazioni normali in questo handle di file.

Errore standard : il processo scrive le informazioni sull'errore in questo handle di file.

È più stupido che posso farcela :-)

Certo, è principalmente per convenzione. Non c'è nulla che ti impedisca di scrivere le informazioni sull'errore nell'output standard, se lo desideri. È anche possibile chiudere totalmente i tre handle di file e aprire i propri file per l'I / O.

All'avvio del processo, dovrebbe già avere questi handle aperti e può semplicemente leggere e / o scrivere su di essi.

Per impostazione predefinita, sono probabilmente collegati al dispositivo terminale (ad es. /dev/tty ) ma le shell ti permetteranno di impostare connessioni tra questi handle e file e / o dispositivi specifici (o persino pipeline ad altri processi) prima dell'avvio del processo (alcuni dei le manipolazioni possibili sono piuttosto intelligenti).

Un esempio è:

my_prog <inputfile 2>errorfile | grep XYZ

che:

  • creare un processo per my_prog .
  • Aperto inputfile come input standard (file handle 0).
  • Aperto errorfile come errore standard (file handle 2).
  • creare un altro processo pergrep .
  • collegare lo standard output di my_progallo standard input di grep.

Re il tuo commento:

Quando apro questi file nella cartella / dev, come mai non riesco mai a vedere l'output di un processo in esecuzione?

È perché non sono file normali. Mentre UNIX presenta tutto come un file in un file system da qualche parte, ciò non lo rende ai livelli più bassi. La maggior parte dei file nel file/dev gerarchia sono dispositivi a caratteri o blocchi, in effetti un driver di dispositivo. Non hanno una dimensione ma hanno un numero di dispositivo maggiore e minore.

Quando li apri, sei connesso al driver del dispositivo anziché a un file fisico e il driver del dispositivo è abbastanza intelligente da sapere che i processi separati devono essere gestiti separatamente.

Lo stesso vale per il /procfilesystem Linux . Questi non sono file reali, solo gateway strettamente controllati per le informazioni del kernel.


1
Questo è per la tua risposta. Sebbene io possa capire lo scopo dei file da ciò che descrivi, mi piacerebbe spostarmi di livello. quando apro questi file nella cartella / dev, come mai non riesco mai a vedere l'output di un processo in esecuzione. Supponiamo che io esegua top sul terminale, non dovrebbe produrre periodicamente i suoi risultati sul file stdout, quindi quando viene aggiornato dovrei essere in grado di vedere un'istanza dell'output stampata su questo file. Ma non è così ... Quindi questi file non sono gli stessi (quelli nella directory / dev).
Shouvik,

7
Perché quelli non sono tecnicamente file. Sono nodi di dispositivo, che indicano un dispositivo specifico su cui scrivere. UNIX può presentarti tutto come un'astrazione di file, ma ciò non lo rende ai livelli più profondi.
paxdiablo,

1
Utilizzare la funzionalità di reindirizzamento della shell. xyz >xyz.outscriverà l'output standard in un file fisico che può essere letto da altri processi. xyz | grep somethingcollegherà xyzstdout a grepstdin più direttamente. Se vuoi un accesso illimitato a un processo che non controlli in quel modo, dovrai cercare qualcosa di simile /proco scrivere codice per filtrare l'output agganciandolo al kernel in qualche modo. Potrebbero esserci altre soluzioni, ma probabilmente sono tutte pericolose l'una dell'altra :-)
paxdiablo

20
@Shouvik, nota che /dev/stdinè un link simbolico a /proc/self/fd/0- il primo descrittore di file che il programma attualmente in esecuzione ha aperto. Quindi, ciò che viene indicato /dev/stdincambierà da programma a programma, perché /proc/self/punta sempre al "programma attualmente in esecuzione". (Qualunque programma stia eseguendo la openchiamata.) /dev/stdinE gli amici sono stati messi lì per rendere più sicuri gli script di shell setuid, e ti hanno permesso di passare il nome del file /dev/stdina programmi che funzionano solo con i file, ma che vuoi controllare in modo più interattivo. (Un giorno questo sarà un trucco utile per te da sapere. :)
sarnold

1
@ CarlosW.Mercado, un file è una manifestazione fisica dei dati. Ad esempio, i bit memorizzati sul disco rigido. Un handle di file è (di solito) un piccolo token utilizzato per fare riferimento a quel file, una volta aperto.
paxdiablo,

62

Sarebbe più corretto dire che stdin, stdoute stderrsono "I / O ruscelli", piuttosto che file. Come hai notato, queste entità non vivono nel filesystem. Ma la filosofia Unix, per quanto riguarda l'I / O, è "tutto è un file". In pratica, che in realtà significa che è possibile utilizzare le stesse funzioni e interfacce di libreria ( printf, scanf, read, write,select , etc.) senza preoccuparsi se il flusso di I / O è collegato ad una tastiera, un file su disco, una presa di corrente, un tubo, o qualche altra astrazione I / O.

La maggior parte dei programmi hanno bisogno di leggere input, output di scrittura, e gli errori di registro, quindi stdin, stdoute stderrsono predefiniti per voi, come vantaggio programmazione. Questa è solo una convenzione e non è applicata dal sistema operativo.


Grazie per i tuoi input. Ti capita di sapere come potrei intercettare il flusso di dati di output di un processo e inviarlo in un mio file?
Shouvik,

51

A complemento delle risposte di cui sopra, ecco un riassunto dei reindirizzamenti: Cheatsheet di reindirizzamenti

EDIT: questo grafico non è del tutto corretto ma non sono sicuro del perché ...

Il grafico dice che 2> & 1 ha lo stesso effetto di &> comunque

ls Documents ABC > dirlist 2>&1
#does not give the same output as 
ls Documents ABC > dirlist &>

4
Il tuo commento combinato con la risposta accettata ha perfettamente senso e spiega chiaramente le cose! Grazie!
Mykola,

1
Un'immagine vale più di mille parole !
tauseef_CuriousAcquista il

22

Temo che la tua comprensione sia completamente all'indietro. :)

Pensa a "standard in", "standard out" e "errore standard" dalla prospettiva del programma , non dalla prospettiva del kernel.

Quando un programma deve stampare output, normalmente stampa su "standard out". Un programma in genere stampa l'output allo standard out printf, che stampa SOLO allo standard out.

Quando un programma deve stampare informazioni sull'errore (non necessariamente eccezioni, si tratta di un costrutto del linguaggio di programmazione, imposto a un livello molto più alto), normalmente stampa su "errore standard". Normalmente lo fa con fprintf, che accetta un flusso di file da utilizzare durante la stampa. Il flusso di file può essere qualsiasi file aperto per la scrittura: standard out, errore standard o qualsiasi altro file che è stato aperto con fopenofdopen .

"standard in" viene utilizzato quando il file deve leggere l'input, utilizzando freado fgets, o getchar.

Ognuno di questi file può essere facilmente reindirizzato dalla shell, in questo modo:

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

Oppure, l'intera enchilada:

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

Esistono due avvertenze importanti: in primo luogo, "standard in", "standard out" e "errore standard" sono solo una convenzione. Sono una convenzione molto forte , ma è solo un accordo che è molto bello poter eseguire programmi come questo:grep echo /etc/services | awk '{print $2;}' | sort e avere gli output standard di ciascun programma agganciati all'input standard del prossimo programma in cantiere.

In secondo luogo, ho fornito le funzioni ISO C standard per lavorare con flussi di file ( FILE *oggetti) - a livello di kernel, sono tutti i descrittori di file ( intriferimenti alla tabella dei file) e operazioni di livello molto inferiore come reade write, che non fare il buffering felice delle funzioni ISO C. Ho pensato di mantenerlo semplice e utilizzare le funzioni più semplici, ma ho pensato lo stesso che dovresti conoscere le alternative. :)


Così è quando il processo viene eseguito che scrive errori su questo file stderr o quando il programma viene compilato dal suo sorgente. Anche quando parliamo di questi file dal punto di vista del compilatore è diverso rispetto a quando viene confrontato con un programma?
Shouvik,

1
@Shouvik, il compilatore è solo un altro programma, con il proprio stdin, stdout e stderr. Quando il compilatore deve scrivere avvisi o errori, li scriverà su stderr. Quando il front-end del compilatore genera codice intermedio per l'assemblatore, potrebbe scrivere il codice intermedio su stdout e l'assemblatore potrebbe accettare il suo input su stdin, ma tutto ciò che sarebbe dietro le quinte dalla tua prospettiva come utente.) un programma compilato, quel programma può scrivere anche errori nel suo errore standard, ma non ha nulla a che fare con la compilazione.
sarnold,

Grazie per quel token di informazioni. Immagino sia abbastanza stupido da parte mia non vederlo in quella prospettiva ...: P
Shouvik,

1
Quindi stai dicendo che lo standard ci aiuta a stampare il programma
babygame0ver

9

stdin

Legge l'input tramite la console (ad es. Input da tastiera). Utilizzato in C con scanf

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

stdout

Produce output sulla console. Utilizzato in C con printf

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

stderr

Produce output "errore" sulla console. Utilizzato in C con fprintf

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

reindirizzamento

La fonte per stdin può essere reindirizzata. Ad esempio, invece di provenire dall'input da tastiera, può provenire da un file ( echo < file.txt) o da un altro programma ( ps | grep <userid>).

Le destinazioni per stdout, stderr possono anche essere reindirizzate. Ad esempio stdout può essere reindirizzato a un file:, ls . > ls-output.txtin questo caso l'output viene scritto nel filels-output.txt . Stderr può essere reindirizzato con 2>.


8

Penso che la gente lo dica stderr dovrebbe essere usata solo per messaggi di errore sia fuorviante.

Dovrebbe anche essere usato per messaggi informativi destinati all'utente che esegue il comando e non per potenziali consumatori a valle dei dati (ad esempio se si esegue una shell shell che concatena più comandi non si desidera messaggi informativi come "ottenere l'articolo 30 di 42424 "per apparire in stdoutquanto confonderanno il consumatore, ma potresti comunque desiderare che l'utente li veda.

Vedi questo per la logica storica:

"Tutti i programmi hanno posto la diagnostica sull'output standard. Ciò ha sempre causato problemi quando l'output è stato reindirizzato in un file, ma è diventato intollerabile quando l'output è stato inviato a un processo ignaro. Tuttavia, non disposto a violare la semplicità dell'ingresso standard- modello di output standard, le persone hanno tollerato questo stato di cose attraverso la v6. Poco dopo Dennis Ritchie ha tagliato il nodo gordiano introducendo il file di errore standard. Questo non era abbastanza. Con la diagnostica delle condutture potrebbe venire da uno dei numerosi programmi in esecuzione contemporaneamente. identificarsi ".


3

L'uso di ps -aux rivela i processi attuali, tutti elencati in / proc / as / proc / (pid) /, chiamando cat / proc / (pid) / fd / 0 stampa tutto ciò che si trova nell'output standard di quel processo penso. Quindi forse

/ proc / (pid) / fd / 0 - File di output standard
/ proc / (pid) / fd / 1 - File di input standard
/ proc / (pid) / fd / 2 - File di errore standard

per esempiola mia finestra del terminale

Ma ha funzionato così bene per / bin / bash altri processi generalmente non avevano nulla in 0 ma molti avevano errori scritti in 2


3

Per informazioni autorevoli su questi file, controlla le pagine man, esegui il comando sul tuo terminale.

$ man stdout 

Ma per una risposta semplice, ogni file è per:

stdout per un flusso in uscita

stdin per un input di flusso

stderr per errori di stampa o messaggi di registro.

Ogni programma unix ha ognuno di quei flussi.


2

stderr non eseguirà il buffering della cache IO, quindi se la nostra applicazione deve stampare informazioni critiche sui messaggi (alcuni errori, eccezioni) per la console o per utilizzarle su file dove è possibile utilizzare stdout per stampare informazioni di registro generali mentre utilizza il buffer IO Cache c'è una possibilità che prima di scrivere i nostri messaggi nell'applicazione file potrebbe chiudersi, lasciando il debug complesso


0

Un file con buffering associato viene chiamato stream e viene dichiarato puntatore a un tipo FILE definito. La funzione fopen () crea alcuni dati descrittivi per un flusso e restituisce un puntatore per designare il flusso in tutte le ulteriori transazioni. Normalmente ci sono tre flussi aperti con puntatori costanti dichiarati nell'intestazione e associati ai file aperti standard. All'avvio del programma tre flussi sono predefiniti e non è necessario aprirli esplicitamente: input standard (per leggere input convenzionali), output standard (per scrivere output convenzionali) ed errore standard (per scrivere output diagnostici). Quando 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

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

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.