Gli script di shell forniscono una funzionalità molto potente:la possibilità di reindirizzare l'output da comandi e script e inviarlo a file, dispositivi o anche come input per altri comandi o script.
Questo articolo è incentrato sull'output di comandi e script.
Tipi di output
I comandi e gli script in una shell possono generare due tipi di output di base:
- STDOUT: Il normale output di un comando/script (descrittore di file 1)
- STDERR: L'output di errore da un comando/script (descrittore di file 2)
Per impostazione predefinita, STDOUT e STDERR vengono inviati allo schermo del tuo terminale.
In termini di input, STDIN per impostazione predefinita legge l'input dalla tastiera (descrittore di file 0). Un descrittore di file è un identificatore univoco per un file o un'altra risorsa I/O.
Come reindirizzare l'output della shell
Esistono diversi modi per reindirizzare l'output da script e comandi della shell.
1. Reindirizza STDOUT
Per i seguenti esempi, userò questo semplice insieme di file:
$ls -la file*
-rw-r--r--. 1 admin2 admin2 7 Mar 27 15:34 file1.txt
-rw-r--r--. 1 admin2 admin2 10 Mar 27 15:34 file2.txt
-rw-r--r--. 1 admin2 admin2 13 Mar 27 15:34 file3.txt
Sto eseguendo un semplice ls
comandi per illustrare STDOUT e STDERR, ma lo stesso principio si applica alla maggior parte dei comandi che esegui da una shell.
Posso reindirizzare l'output standard a un file utilizzando ls file* > my_stdout.txt
:
$ls file* > my_stdout.txt
$ cat my_stdout.txt
file1.txt
file2.txt
file3.txt
Successivamente, eseguo un comando simile, ma con un 1
prima di >
. Reindirizzamento utilizzando il >
segnale è lo stesso dell'utilizzo di 1>
per farlo:sto dicendo alla shell di reindirizzare lo STDOUT a quel file. Se ometto il descrittore di file, viene utilizzato STDOUT per impostazione predefinita. Posso dimostrarlo eseguendo sdiff
comando per mostrare l'output di entrambi i comandi affiancati:
$ls file* 1> my_other_stdout.txt
$sdiff my_stdout.txt my_other_stdout.txt
file1.txt file1.txt
file2.txt file2.txt
file3.txt file3.txt
Come puoi vedere, entrambi gli output hanno lo stesso contenuto.
2. Reindirizza STDERR
Ora, cos'ha di speciale STDERR? Per dimostrare, introdurrò una condizione di errore nell'esempio precedente con ls file* non-existing-file* > my_normal_output.txt
:
Ecco il risultato:
ImmagineEcco alcune osservazioni dal test di cui sopra:
- L'output sui file esistenti viene inviato correttamente al file di destinazione.
- L'errore (che viene visualizzato quando provo a elencare qualcosa che non esiste) viene inviato allo schermo. Questo è il luogo predefinito in cui vengono inviati gli errori a meno che non vengano reindirizzati.
[ Scarica un cheat sheet per gli script di Bash Shell. ]
Successivamente, reindirizzerò l'output dell'errore facendo riferimento al descrittore di file 2 in modo esplicito con ls file* non-existing-file* > my_normal_output.txt 2> my_error_output.txt:
Nell'esempio sopra:
- Il
ls
comando non visualizza il messaggio di errore sullo schermo come prima. - L'output normale contiene ciò che mi aspetto.
- Il messaggio di errore viene inviato a
my_error_output.txt
file.
3. Invia STDOUT e STDERR allo stesso file
Un'altra situazione comune è inviare sia STDOUT che STDERR allo stesso file:
$ls file* non-existing-file* > my_consolidated_output.txt 2>&1
$ cat my_consolidated_output.txt
ls: cannot access 'non-existing-file*': No such file or directory
file1.txt
file2.txt
file3.txt
In questo esempio, tutto l'output (normale ed errore) viene inviato allo stesso file.
Il 2>&1
costruzione significa "inviare lo STDERR allo stesso posto in cui stai inviando lo STDOUT ."
4. Reindirizza l'output, ma aggiungi il file
In tutti gli esempi precedenti, ogni volta che reindirizzavo un output, usavo un singolo >
, che significa "invia qualcosa a questo file e avvia il file da zero ." Di conseguenza, se il file di destinazione esiste, viene sovrascritto.
Se voglio aggiungere in un file esistente, devo usare >>
. Se il file non esiste già, verrà creato:
$echo "Adding stuff to the end of a file" >> my_output.txt
$cat my_output.txt
file1.txt
file2.txt
file3.txt
Adding stuff to the end of a file
5. Reindirizzamento a un altro processo o da nessuna parte
Gli esempi precedenti riguardano il reindirizzamento dell'output a un file, ma puoi anche reindirizzare gli output ad altri processi o dev/null
.
L'invio di output ad altri processi è una delle funzionalità più potenti di una shell. Per questa attività, usa il |
simbolo (pipe), che invia l'output di un comando all'input del comando successivo:
ps -ef | grep chrome | grep -v grep | wc -l
21
L'esempio sopra elenca i miei processi, filtra quelli che contengono la stringa chrome , ignora la riga relativa al mio grep
comando e conta le righe risultanti. Se voglio inviare l'output a un file, aggiungo >
e un nome file alla fine della catena.
Infine, ecco un esempio in cui voglio ignorare uno degli output, lo STDERR:
$tar cvf my_files.tar file* more-non-existing*
file1.txt
file2.txt
file3.txt
tar: more-non-existing*: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
Perché il tar
comando non ha trovato alcun file con nomi che iniziano con more-non-existing
, alla fine vengono visualizzati alcuni messaggi di errore.
Supponiamo che io crei degli script e non mi importi di vedere o catturare questi errori (lo so, nella vita reale, dovresti prevenire e gestire gli errori, non semplicemente ignorarli):
$tar cvf my_files.tar file* more-non-existing* 2> /dev/null
file1.txt
file2.txt
file3.txt
Il /dev/null
è un file dispositivo speciale che è come un "buco nero":ciò che invii lì scompare.
[ Scarica questa guida all'installazione di applicazioni su Linux. ]
6. Usa il reindirizzamento in uno script
Immagine
=== SUMMARY OF INVESTIGATION OF chrome ===
Date/Time of the execution: 2022-03-25 18:05:50
Number of processes found.: 5
PIDs:
1245475
1249558
1316941
1382460
1384452
Questo script molto semplice esegue le seguenti operazioni:
- Riga 3:esegue un comando nel sistema operativo e salva nella variabile DATE_TIME.
- Riga 6:esegue
ps
comando e reindirizza agrep
e in un file.- Invece di inviare l'output a un file, potrei inviarlo a una variabile (come nella riga 3), ma in questo caso voglio eseguire altre azioni usando lo stesso output, quindi lo acquisisco. In una situazione più realistica, avere il file potrebbe essere utile anche durante lo sviluppo o la risoluzione dei problemi, così posso indagare più facilmente su cosa genera il comando.
- Riga 8:esegue comandi aggiuntivi, reindirizza gli output a
wc
e assegna il risultato a una variabile. - Riga 9:utilizza
awk
per selezionare solo la colonna 2 dall'output e ordinarla in ordine decrescente (solo per il gusto di aggiungere un'altra pipe).
Concludi
Questi erano alcuni esempi di reindirizzamento di STDOUT e STDERR. Mettendo tutto questo insieme, ti rendi conto di quanto possa essere potente il reindirizzamento. Concatenando i singoli comandi, manipolandone l'output e utilizzando il risultato come input per il comando successivo, è possibile eseguire attività che altrimenti potrebbero richiedere lo sviluppo di uno script o di un programma. Potresti anche incorporare la tecnica in altri script, usando tutto come elementi costitutivi.