Cosa sono stdin, stdout e stderr su Linux?

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

Gli stream si uniscono a due punti

Non appena inizi a conoscere i sistemi operativi 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 sorgente 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à verrà collegata alla finestra del terminale, collegata a una pipe o reindirizzata a un file o un altro comando, in base alla riga di comando che ha avviato il comando.

I flussi standard di Linux

In Linux, stdin è il flusso di input standard. Accetta il testo come input. L’output di testo dal comando alla shell viene fornito 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 il 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é.

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: stdout
2: stderr

Reagire a pipe e reindirizzamenti

Per facilitare l’introduzione di un argomento da parte di qualcuno, una tecnica comune è insegnare una versione semplificata dell’argomento. Ad esempio, con la grammatica, ci viene detto che la regola è “I prima di E, tranne dopo C.” Ma in realtà, lì sono più eccezioni a questa regola che ci sono casi che lo obbediscono.

  Come installare l'editor markdown Zettlr su Linux

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 di dove terminano i suoi tre flussi standard. Un processo dovrebbe preoccuparsi se il suo output va al terminale o viene reindirizzato in un file? Può anche dire se il suo input proviene dalla tastiera o viene convogliato in esso da un altro processo?

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

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

ls

È in una finestra di terminale

ls | cat

Viene visualizzato in una finestra di terminale

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

ls > capture.txt

ls> capture.txt in una finestra di terminale “width =” 646 ″ height = “57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ”  onerror = “this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p>
<pre> cat capture.txt </pre>
<p> <img loading =

Reindirizzamento di stdout e stderr

C’è un vantaggio nell’avere messaggi di errore consegnati da uno stream dedicato. Significa che possiamo reindirizzare l’output di un comando (stdout) a un file e continuare a vedere eventuali messaggi di errore (stderr) nella finestra del terminale. Puoi reagire agli errori se necessario, non appena si verificano. Inoltre impedisce ai messaggi di errore di contaminare il file in cui stdout è stato reindirizzato.

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

#!/bin/bash

echo "About to try to access a file that doesn't exist"
cat bad-filename.txt

Rendi eseguibile lo script con questo comando:

chmod +x error.sh

La prima riga dello script fa eco il testo alla 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:

./error.sh

./error.sh in una finestra di terminale

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

output dallo script error.sh in una finestra di terminale

Proviamo a reindirizzare l’output su un file:

./error.sh > capture.txt

./error.sh> capture.txt in una finestra di terminale “width =” 646 ″ height = “57” onload = “pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”  onerror = “this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p>
<p> Il messaggio di errore fornito tramite stderr viene ancora inviato alla finestra del terminale.  Possiamo controllare il contenuto del file per vedere se l’output di stdout è andato al file. </p>
<pre> cat capture.txt </pre>
<p> <img loading =

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

contenuto di capture.txt in una finestra di terminale

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.

  Come installare KDE Plasma 5 su Linux

Per reindirizzare esplicitamente lo stdout, utilizzare questa istruzione di reindirizzamento:

1>

Per reindirizzare esplicitamente stderr, usa questa istruzione di reindirizzamento:

2>

Riproviamo il nostro test, e questa volta useremo 2>:

./error.sh 2> capture.txt

./error.sh 2> capture.txt in una finestra di terminale “width =” 646 ″ height = “57” onload = “pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”  onerror = “this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p>
<p> Il messaggio di errore viene reindirizzato e il messaggio echo stdout viene inviato alla finestra del terminale: </p>
<p > <img class =

Il messaggio stderr è in capture.txt come previsto.

contenuto del file capture.txt in una finestra di terminale

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?

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

./error.sh 1> capture.txt 2> error.txt in una finestra di terminale “width =” 646 ″ height = “57” onload = “pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”  onerror = “this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p>
<p> Poiché entrambi i flussi di output, standard output ed errore standard, vengono reindirizzati ai file, non vi è alcun output visibile in la finestra del terminale.  Si torna al prompt della riga di comando come se non fosse successo nulla. </p>
<p> <img loading =

Controlliamo il contenuto di ogni file:

cat capture.txt
cat error.txt

contenuto di capture.txt e error.txt in una finestra di terminale

Reindirizzamento di stdout e stderr allo stesso file

È chiaro, 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 lo stream stdout al file capture.txt. > è una scorciatoia per 1>.
2> & 1: utilizza l’istruzione di reindirizzamento &>. Questa istruzione ti permette di dire alla shell di fare in modo che uno stream arrivi alla stessa destinazione di un altro stream. In questo caso, stiamo dicendo “reindirizza lo stream 2, stderr, alla stessa destinazione a cui viene reindirizzato lo stream 1, stdout”.

./error.sh> capture.txt 2 e> 1 in una finestra di terminale “width =” 646 ″ height = “57 ″ onload =” pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this); ”  onerror = “this.onerror = null; pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon (this);”> </p>
<p> Nessun output visibile.  È incoraggiante. </p>
<p> <img loading =

Controlliamo il file capture.txt e vediamo cosa contiene.

cat capture.txt

contenuto di capture.txt in una finestra di terminale

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

Per fare in modo che l’output di un flusso venga reindirizzato e gettato 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 suo comportamento di conseguenza. Possiamo farlo nei nostri script? Sì possiamo. Ed è una tecnica molto facile da capire e utilizzare.

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

#!/bin/bash

if [ -t 0 ]; then

  echo stdin coming from keyboard
 
else

  echo stdin coming from a pipe or a file
 
fi

Usa il seguente comando per renderlo eseguibile:

chmod +x input.sh

La parte intelligente è il prova all’interno delle 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.

  Come utilizzare il comando stringhe su Linux

Se stdin è connesso a una finestra di terminale il test sarà vero. Se stdin è connesso a un file o una pipe, il test fallirà.

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

./input.sh 

./input.sh <dummy.txt in una finestra di terminale

The output shows that the script recognizes that the input isn’t coming from a keyboard, it is coming from a file. If you chose to, you could vary your script’s behavior accordingly.

output dallo script in una finestra di terminale

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

manichino gatto.txt |  ./input.sh

manichino gatto.txt |  ./input.sh in una finestra di terminale

Lo script riconosce che il suo input viene convogliato in esso. O più precisamente, riconosce ancora una volta che il flusso stdin non è connesso a una finestra di terminale.

output dello script in una finestra di terminale

Eseguiamo lo script senza pipe né redirect.

./input.sh

./input.sh in una finestra di terminale

Il flusso stdin è connesso alla finestra del terminale e lo script lo riporta di conseguenza.

Per controllare 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

if [ -t 1 ]; then

echo stdout is going to the terminal window
 
else

echo stdout is being redirected or piped
 
fi

Usa il seguente comando 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. Condurremo l'output tramite cat.

./output | cat

./output |  gatto in una finestra di terminale

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

output dello script in una finestra di terminale

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

./output.sh > capture.txt

./output.sh> capture.txt in una finestra di terminale

Non vi è alcun output nella finestra del terminale, torniamo silenziosamente al prompt dei comandi. Come ci aspetteremmo.

output dello script in una finestra di terminale

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

cat capture.sh

cat capture.sh in una finestra di terminale

Di nuovo, il semplice test nel nostro script rileva che il flusso stdout non viene inviato direttamente a una finestra di terminale.

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

./output.sh

./output.sh in una finestra di terminale

Ed è esattamente quello che vediamo.

output dello script in una finestra di terminale

Flussi di coscienza

Sapere come sapere se i tuoi script sono collegati alla finestra del terminale, o 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 vengano visualizzati sullo schermo o su un file. I messaggi di errore possono essere registrati in un file diverso dal normale output del programma.

Come di solito, una maggiore conoscenza offre più opzioni.