Cosa sono stdin, stdout e stderr su Linux?

Pubblicato: 2022-01-29
Finestra del terminale su un computer Linux
Fatmawati Achmad Zaenuri/Shutterstock.com

stdin , stdout e stderr sono tre flussi di dati creati quando si avvia un comando Linux. Puoi usarli per sapere se i tuoi script vengono reindirizzati o reindirizzati. Ti mostriamo come.

Gli stream uniscono due punti

Non appena inizi a conoscere i sistemi operativi simili a Linux e Unix, ti imbatterai nei termini stdin , stdout e stederr . Questi sono tre flussi standard che vengono stabiliti quando viene eseguito un comando Linux. In informatica, un flusso è qualcosa che può trasferire dati. Nel caso di questi flussi, i dati sono testo.

I flussi di dati, come i flussi d'acqua, hanno due estremità. Hanno una fonte e un deflusso. Qualunque sia il comando Linux che stai utilizzando fornisce un'estremità di ogni flusso. L'altra estremità è determinata dalla shell che ha lanciato il comando. Quell'estremità sarà collegata alla finestra del terminale, collegata a una pipe o reindirizzata a un file o altro comando, in base alla riga di comando che ha lanciato il comando.

I flussi standard di Linux

In Linux, stdin è il flusso di input standard. Questo accetta il testo come input. L'output di testo dal comando alla shell viene consegnato tramite il flusso stdout (standard out). I messaggi di errore del comando vengono inviati tramite il flusso stderr (errore standard).

Quindi puoi vedere che ci sono due flussi di output, stdout e stderr , e un flusso di input, stdin . Poiché i messaggi di errore e l'output normale hanno ciascuno il proprio condotto per portarli alla finestra del terminale, possono essere gestiti indipendentemente l'uno dall'altro.

I flussi vengono gestiti come file

I flussi in Linux, come quasi tutto il resto, vengono trattati come se fossero file. Puoi leggere il testo da un file e puoi scrivere del testo in un file. Entrambe queste azioni implicano un flusso di dati. Quindi il concetto di gestire un flusso di dati come un file non è un granché.

Annuncio pubblicitario

A ogni file associato a un processo viene assegnato un numero univoco per identificarlo. Questo è noto come descrittore di file. Ogni volta che è necessario eseguire un'azione su un file, il descrittore di file viene utilizzato per identificare il file.

Questi valori sono sempre usati per stdin , stdout, e stderr :

  • 0 : stdin
  • 1 : normale
  • 2 : stderr

Reagire a tubi e reindirizzamenti

Per facilitare l'introduzione di qualcuno a una materia, una tecnica comune consiste nell'insegnare una versione semplificata dell'argomento. Ad esempio, con la grammatica, ci viene detto che la regola è "I prima di E, eccetto dopo C". Ma in realtà, ci sono più eccezioni a questa regola di quanti casi la obbediscano.

Allo stesso modo, quando si parla di stdin , stdout e stderr è conveniente tirare fuori l'assioma accettato che un processo non sa né si preoccupa dove terminano i suoi tre flussi standard. Un processo dovrebbe preoccuparsi se il suo output sta andando al terminale o viene reindirizzato in un file? Può anche dire se il suo input proviene dalla tastiera o viene inviato da un altro processo?

In realtà, un processo lo sa, o almeno può scoprirlo, se sceglie di controllare, e può cambiare il suo comportamento di conseguenza se l'autore del software decide di aggiungere quella funzionalità.

Annuncio pubblicitario

Possiamo vedere molto facilmente questo cambiamento nel comportamento. Prova questi due comandi:

 ls 

 ls | gatto 

Il comando ls si comporta in modo diverso se il suo output ( stdout ) viene reindirizzato a un altro comando. È ls che passa a un output di una singola colonna, non è una conversione eseguita da cat . E ls fa la stessa cosa se il suo output viene reindirizzato:

 ls > capture.txt 

 cat capture.txt 

Reindirizzamento stdout e stderr

C'è un vantaggio nell'avere messaggi di errore consegnati da un flusso dedicato. Significa che possiamo reindirizzare l'output di un comando ( stdout ) su un file e continuare a vedere eventuali messaggi di errore ( stderr ) nella finestra del terminale. Puoi reagire agli errori, se necessario, quando si verificano. Impedisce inoltre ai messaggi di errore di contaminare il file in cui è stato reindirizzato stdout .

Digita il seguente testo in un editor e salvalo in un file chiamato error.sh.

 #!/bin/bash

echo "Sto per provare ad accedere a un file che non esiste"
cat nome-file errato.txt

Rendi eseguibile lo script con questo comando:

 chmod +x errore.sh

La prima riga dello script fa eco al testo nella finestra del terminale, tramite il flusso stdout . La seconda riga tenta di accedere a un file che non esiste. Questo genererà un messaggio di errore che viene consegnato tramite stderr .

Esegui lo script con questo comando:

 ./errore.sh 

Possiamo vedere che entrambi i flussi di output, stdout e stderr , sono stati visualizzati nelle finestre del terminale.

Proviamo a reindirizzare l'output su un file:

 ./error.sh > capture.txt 

Annuncio pubblicitario

Il messaggio di errore che viene consegnato tramite stderr viene comunque inviato alla finestra del terminale. Possiamo controllare il contenuto del file per vedere se l'output stdout è andato al file.

 cat capture.txt 

L'output di stdin è stato reindirizzato al file come previsto.

Il simbolo di reindirizzamento > funziona con stdout per impostazione predefinita. È possibile utilizzare uno dei descrittori di file numerici per indicare quale flusso di output standard si desidera reindirizzare.

Per reindirizzare esplicitamente stdout , utilizzare questa istruzione di reindirizzamento:

 1>

Per reindirizzare esplicitamente stderr , utilizzare questa istruzione di reindirizzamento:

 2>

Proviamo di nuovo il nostro test e questa volta useremo 2> :

 ./error.sh 2> capture.txt 

Il messaggio di errore viene reindirizzato e il messaggio echo stdout viene inviato alla finestra del terminale:

Vediamo cosa c'è nel file capture.txt.

 cat capture.txt 

Il messaggio stderr è in capture.txt come previsto.

Reindirizzamento Sia stdout che stderr

Sicuramente, se possiamo reindirizzare stdout o stderr a un file indipendentemente l'uno dall'altro, dovremmo essere in grado di reindirizzarli entrambi contemporaneamente, su due file diversi?

Annuncio pubblicitario

Sì possiamo. Questo comando indirizzerà stdout a un file chiamato capture.txt e stderr a un file chiamato error.txt.

 ./error.sh 1> capture.txt 2> error.txt 

Poiché entrambi i flussi di output, output standard ed errore standard, vengono reindirizzati ai file, non è presente alcun output visibile nella finestra del terminale. Torniamo al prompt della riga di comando come se non fosse successo nulla.

Controlliamo il contenuto di ogni file:

 cat capture.txt
 errore gatto.txt 

Reindirizzamento di stdout e stderr allo stesso file

Va bene, abbiamo ciascuno dei flussi di output standard che vanno al proprio file dedicato. L'unica altra combinazione che possiamo fare è inviare sia stdout che stderr allo stesso file.

Possiamo ottenere ciò con il seguente comando:

 ./error.sh > capture.txt 2>&1

Analizziamolo.

  • ./error.sh : avvia il file di script error.sh.
  • > capture.txt : reindirizza il flusso stdout al file capture.txt. > è l'abbreviazione di 1> .
  • 2>&1 : utilizza l'istruzione di reindirizzamento &>. Questa istruzione ti consente di dire alla shell di fare in modo che un flusso raggiunga la stessa destinazione di un altro flusso. In questo caso, stiamo dicendo "redirect stream 2, stderr , alla stessa destinazione a cui viene reindirizzato lo stream 1, stdout ."

Non è presente alcun output visibile. Questo è incoraggiante.

Controlliamo il file capture.txt e vediamo cosa contiene.

 cat capture.txt 

Entrambi i flussi stdout e stderr sono stati reindirizzati a un unico file di destinazione.

Per fare in modo che l'output di un flusso venga reindirizzato e buttato via silenziosamente, indirizza l'output a /dev/null .

Rilevamento del reindirizzamento all'interno di uno script

Abbiamo discusso di come un comando può rilevare se uno qualsiasi dei flussi viene reindirizzato e può scegliere di modificare il proprio comportamento di conseguenza. Possiamo realizzare questo nei nostri script? Sì possiamo. Ed è una tecnica molto facile da capire e da utilizzare.

Annuncio pubblicitario

Digita il seguente testo in un editor e salvalo come input.sh.

 #!/bin/bash

se [ -t 0 ]; poi

  echo stdin proveniente dalla tastiera
 
altro

  echo stdin proveniente da una pipe o da un file
 
fi

Utilizzare il comando seguente per renderlo eseguibile:

 chmod +x input.sh

La parte intelligente è il test tra parentesi quadre. L'opzione -t (terminale) restituisce true (0) se il file associato al descrittore di file termina nella finestra del terminale. Abbiamo usato il descrittore di file 0 come argomento del test, che rappresenta stdin .

Se stdin è collegato a una finestra di terminale, il test risulterà vero. Se stdin è connesso a un file o una pipe, il test avrà esito negativo.

Possiamo usare qualsiasi file di testo conveniente per generare input per lo script. Qui ne stiamo usando uno chiamato dummy.txt.

 ./input.sh < dummy.txt 

L'output mostra che lo script riconosce che l'input non proviene da una tastiera, ma da un file. Se lo desideri, puoi variare di conseguenza il comportamento del tuo script.

Annuncio pubblicitario

Era con un reindirizzamento di file, proviamolo con una pipe.

 cat dummy.txt | ./input.sh 

Lo script riconosce che il suo input viene inviato tramite pipe. O più precisamente, riconosce ancora una volta che lo stream stdin non è connesso a una finestra di terminale.

Eseguiamo lo script senza pipe né reindirizzamenti.

 ./input.sh 

Il flusso stdin è collegato alla finestra del terminale e lo script lo segnala di conseguenza.

Per verificare la stessa cosa con il flusso di output, abbiamo bisogno di un nuovo script. Digita quanto segue in un editor e salvalo come output.sh.

 #!/bin/bash

se [ -t 1 ]; poi

echo stdout sta andando alla finestra del terminale
 
altro

echo stdout viene reindirizzato o reindirizzato
 
fi

Utilizzare il comando seguente per renderlo eseguibile:

 chmod +x input.sh

L'unica modifica significativa a questo script è nel test tra parentesi quadre. Stiamo usando la cifra 1 per rappresentare il descrittore di file per stdout .

Proviamolo. Invieremo l'output tramite cat .

 ./output | gatto 

Annuncio pubblicitario

Lo script riconosce che il suo output non va direttamente a una finestra del terminale.

Possiamo anche testare lo script reindirizzando l'output su un file.

 ./output.sh > capture.txt 

Non c'è output nella finestra del terminale, siamo tornati silenziosamente al prompt dei comandi. Come ci aspetteremmo.

Possiamo guardare all'interno del file capture.txt per vedere cosa è stato catturato. Utilizzare il comando seguente per farlo.

 cat capture.sh 

Anche in questo caso, il semplice test nel nostro script rileva che il flusso stdout non viene inviato direttamente a una finestra di terminale.

Annuncio pubblicitario

Se eseguiamo lo script senza pipe o reindirizzamenti, dovrebbe rilevare che stdout viene consegnato direttamente alla finestra del terminale.

 ./output.sh 

Ed è esattamente quello che vediamo.

Flussi di coscienza

Sapere come sapere se i tuoi script sono collegati alla finestra del terminale, a una pipe o vengono reindirizzati, ti consente di regolare il loro comportamento di conseguenza.

La registrazione e l'output diagnostico possono essere più o meno dettagliati, a seconda che si tratti di una schermata o di un file. I messaggi di errore possono essere registrati in un file diverso rispetto al normale output del programma.

Come di solito accade, una maggiore conoscenza porta più opzioni.

CORRELATI: I migliori laptop Linux per sviluppatori e appassionati