Sarebbe più corretto dire che stdin
, stdout
e stderr
sono "flussi I/O" 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, ciò significa davvero che puoi utilizzare le stesse funzioni e interfacce di libreria (printf
,scanf
, read
, write
, select
, ecc.) senza preoccuparsi se il flusso di I/O è connesso a una tastiera, un file su disco, un socket, una pipe o qualche altra astrazione di I/O.
La maggior parte dei programmi deve leggere l'input, scrivere l'output e registrare gli errori, quindi stdin
, stdout
e stderr
sono predefiniti per te, per comodità di programmazione. Questa è solo una convenzione e non viene applicata dal sistema operativo.
Temo che la tua comprensione sia completamente al contrario. :)
Pensa a "standard in", "standard out" e "standard error" del programma punto di vista, non dal punto di vista del kernel.
Quando un programma ha bisogno di stampare l'output, normalmente stampa su "standard out". Un programma tipicamente stampa l'output su standard out con printf
, che stampa SOLO su standard out.
Quando un programma ha bisogno di stampare informazioni sull'errore (non necessariamente eccezioni, quelle sono 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, standard error o qualsiasi altro file aperto con fopen
o fdopen
.
"standard in" viene utilizzato quando il file deve leggere l'input, utilizzando fread
o fgets
o getchar
.
Tutti questi file possono essere facilmente reindirizzati 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
Ci sono due importanti avvertenze:in primo luogo, "standard in", "standard out" e "standard error" sono solo una convenzione. Sono molto forti convenzione, ma è solo un accordo sul fatto che è molto bello poter eseguire programmi come questo:grep echo /etc/services | awk '{print $2;}' | sort
e avere gli output standard di ogni programma agganciati allo standard input del programma successivo nella pipeline.
In secondo luogo, ho fornito le funzioni ISO C standard per lavorare con flussi di file (FILE *
objects) -- a livello di kernel, sono tutti descrittori di file (int
riferimenti alla tabella dei file) e operazioni di livello inferiore come read
e write
, che non eseguono il felice buffering delle funzioni ISO C. Ho pensato di mantenerlo semplice e utilizzare le funzioni più semplici, ma ho pensato comunque che dovresti conoscere le alternative. :)
Immissione standard - questo è l'handle del file che il tuo processo legge per ottenere informazioni da te.
Uscita standard - il tuo processo scrive l'output convenzionale su questo handle di file.
Errore standard - il tuo processo scrive l'output diagnostico su questo handle di file.
È più stupido che posso farlo :-)
Naturalmente, questo è principalmente per convenzione. Non c'è nulla che ti impedisca di scrivere le tue informazioni diagnostiche sullo standard output, se lo desideri. Puoi persino chiudere completamente i tre handle di file e aprire i tuoi file per l'I/O.
Quando il tuo processo si avvia, dovrebbe già avere questi handle aperti e può solo leggere e/o scrivere su di essi.
Per impostazione predefinita, sono probabilmente connessi al tuo dispositivo terminale (ad esempio, /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 che il tuo processo inizi (alcune delle manipolazioni possibili sono piuttosto intelligenti).
Un esempio è:
my_prog <inputfile 2>errorfile | grep XYZ
che:
- crea un processo per
my_prog
. - apri
inputfile
come input standard (file handle 0). - apri
errorfile
come errore standard (file handle 2). - creane un altro processo per
grep
. - allega lo standard output di
my_prog
all'input standard digrep
.
Per quanto riguarda il tuo commento:
Quando apro questi file nella cartella /dev, come mai non riesco a vedere l'output di un processo in esecuzione?
È perché non sono file normali. Mentre UNIX presenta tutto come file in un file system da qualche parte, ciò non lo rende tale ai livelli più bassi. La maggior parte dei file nel /dev
gerarchia sono dispositivi a caratteri oa 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 processi separati devono essere gestiti separatamente.
Lo stesso vale per Linux /proc
file system. Quelli non sono file reali, solo gateway strettamente controllati per le informazioni del kernel.
A complemento delle risposte di cui sopra, ecco un riassunto sui reindirizzamenti:
EDIT:questa grafica non è del tutto corretta.
Il primo esempio non usa affatto stdin, passa "ciao" come argomento al comando echo.
Il grafico dice anche che 2>&1 ha lo stesso effetto di &> tuttavia
ls Documents ABC > dirlist 2>&1
#does not give the same output as
ls Documents ABC > dirlist &>
Questo perché &> richiede un file a cui reindirizzare e 2>&1 sta semplicemente inviando stderr in stdout