103.4 Lezione 1
Certificazione: |
LPIC-1 (101) |
---|---|
Versione: |
5.0 |
Argomento: |
103 Comandi GNU e Unix |
Obiettivo: |
103.4 Utilizzare stream, pipe e reindirizzamenti |
Lezione: |
1 di 2 |
Introduzione
Tutti i programmi per computer seguono lo stesso principio generale: i dati ricevuti da qualche fonte vengono trasformati per generare un risultato intelligibile. Nel contesto della shell di Linux, l’origine dati può essere un file locale, un file remoto, un dispositivo (come una tastiera), e altro ancora. L’output del programma viene solitamente visualizzato su uno schermo, ma è anche comune memorizzare i dati di output in un filesystem locale, inviarlo a un dispositivo remoto, riprodurlo tramite altoparlanti audio, ecc.
I sistemi operativi ispirati a Unix, come Linux, offrono una grande varietà di metodi di input/output. In particolare il metodo dei file descriptors consente di associare dinamicamente numeri interi ai canali dati, in modo che un processo possa riferirli come propri flussi di dati di input/output.
I processi Linux standard hanno tre canali di comunicazione aperti per impostazione predefinita: il canale standard input (il più delle volte chiamato semplicemente stdin), il canale standard output (stdout) e il canale standard error (stderr). I descrittori di file numerici assegnati a questi canali sono 0
per stdin, 1
per stdout e 2
per stderr. I canali di comunicazione sono anche accessibili tramite i dispositivi speciali /dev/stdin
, /dev/stdout
e /dev/stderr
.
Questi tre canali di comunicazione standard consentono ai programmatori di scrivere codice che legge e scrive dati senza preoccuparsi del tipo di supporto da cui provengono o a cui vanno. Per esempio, se un programma ha bisogno di un insieme di dati come input, può semplicemente chiedere i dati allo standard input e qualsiasi cosa venga utilizzata come standard input fornirà quei dati. Allo stesso modo, il metodo più semplice che un programma possa utilizzare per visualizzare il proprio output è scriverlo nell’output standard. In una sessione di shell standard, la tastiera è definita come stdin e lo schermo del monitor è definito come stdout e stderr.
La shell Bash ha la capacità di riassegnare i canali di comunicazione durante il caricamento di un programma. Consente, per esempio, di sovrascrivere lo schermo come output standard e di utilizzare un file nel filesystem locale come stdout.
Reindirizzamenti
La riassegnazione del descrittore di file di un canale nell’ambiente della shell è chiamata redirect. Un reindirizzamento è definito da un carattere speciale all’interno della riga di comando. Per esempio, per reindirizzare l’output standard di un processo su un file, il simbolo maggiore di >
è posizionato alla fine del comando e seguito dal percorso del file che riceverà l’output reindirizzato:
$ cat /proc/cpuinfo >/tmp/cpu.txt
Per impostazione predefinita, viene reindirizzato solo il contenuto che arriva a stdout. Ciò accade perché il valore numerico del descrittore di file deve essere specificato appena prima del simbolo maggiore di e, se non specificato, Bash reindirizza l’output standard. Pertanto, usare >
equivale a usare 1>
(il valore del descrittore di file di stdout è 1
).
Per catturare il contenuto di stderr, si dovrebbe invece usare il reindirizzamento 2>
. La maggior parte dei programmi da riga di comando invia informazioni di debug e messaggi di errore al canale di errore standard. È possibile, per esempio, catturare il messaggio di errore innescato da un tentativo di leggere un file inesistente:
$ cat /proc/cpu_info 2>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory
Sia stdout che stderr vengono reindirizzati alla stessa destinazione con &>
o >&
. È importante non inserire spazi accanto alla e commerciale, altrimenti Bash lo prenderà come istruzione per eseguire il processo in background e non per eseguire il reindirizzamento.
La destinazione deve essere un percorso a un file scrivibile, come /tmp/cpu.txt
, o un descrittore di file scrivibile. La destinazione di un descrittore di file è rappresentata da una e commerciale seguita dal valore numerico del descrittore di file. Per esempio, 1>&2
reindirizza stdout a stderr. Per fare l’opposto, da stderr a stdout, dovrebbero essere usati 2>&1
.
Sebbene non sia molto utile, dato che esiste un modo più breve per eseguire la stessa operazione, è possibile reindirizzare stderr a stdout e quindi reindirizzarlo a un file. Per esempio, un redirect per scrivere sia stderr che stdout in un file chiamato log.txt
può essere scritto come >log.txt 2>&1
. Tuttavia, il motivo principale per reindirizzare stderr a stdout è consentire l’analisi dei messaggi di debug e di errore. È possibile reindirizzare lo standard output di un programma allo standard input di un altro programma, ma non è possibile reindirizzare direttamente lo standard error allo standard input di un altro programma. Pertanto, i messaggi del programma inviati a stderr devono prima essere reindirizzati a stdout per essere letti dallo stdin di un altro programma.
Per scartare semplicemente l’output di un comando, il suo contenuto può essere reindirizzato al file speciale /dev/null
. Per esempio, >log.txt 2>/dev/null
salva il contenuto di stdout nel file log.txt
e scarta lo stderr. Il file /dev/null
è scrivibile da qualsiasi utente ma nessun dato può essere recuperato da esso, poiché non è memorizzato da nessuna parte.
Viene visualizzato un messaggio di errore se la destinazione specificata non è scrivibile (se il percorso punta a una directory o a un file di sola lettura) e non viene apportata alcuna modifica alla destinazione. Tuttavia, un reindirizzamento dell’output sovrascrive una destinazione scrivibile esistente senza alcuna conferma. I file vengono sovrascritti dai reindirizzamenti di output a meno che non sia abilitata l’opzione Bash noclobber
, che può essere eseguita per la sessione corrente con il comando set -o noclobber
o set -C
:
$ set -o noclobber $ cat /proc/cpu_info 2>/tmp/error.txt -bash: /tmp/error.txt: cannot overwrite existing file
Per annullare l’impostazione dell’opzione noclobber
per la sessione corrente, eseguire set +o noclobber
o set +C
. Per rendere persistente l’opzione noclobber
, deve essere inclusa nel profilo Bash dell’utente o nel profilo a livello di sistema.
Anche con l’opzione noclobber
abilitata è possibile aggiungere dati reindirizzati a contenuto esistente. Ciò si ottiene con un reindirizzamento scritto con due simboli maggiore di >>
:
$ cat /proc/cpu_info 2>>/tmp/error.txt $ cat /tmp/error.txt cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Nell’esempio precedente, il nuovo messaggio di errore è stato aggiunto a quello esistente nel file /tmp/error.txt
. Se il file non esiste ancora, verrà creato con i nuovi dati.
Anche l’origine dati dello standard input di un processo può essere riassegnata. Il simbolo minore di <
viene utilizzato per reindirizzare il contenuto di un file allo stdin di un processo. In questo caso, i dati scorrono da destra a sinistra: si assume che il descrittore riassegnato sia 0 a sinistra del simbolo minore di e l’origine dati (un percorso di un file) deve essere a destra del simbolo minore di. Il comando uniq
, come la maggior parte delle utilità della riga di comando per l’elaborazione del testo, accetta i dati inviati allo stdin per impostazione predefinita:
$ uniq -c </tmp/error.txt 2 cat: /proc/cpu_info: No such file or directory
L’opzione -c
fa visualizzare a uniq
quante volte una riga ripetuta appare nel testo. Poiché il valore numerico del descrittore di file reindirizzato è stato soppresso, il comando di esempio è equivalente a uniq -c 0</tmp/error.txt
. Usare un descrittore di file diverso da 0
in un reindirizzamento dell’input ha senso solo in contesti specifici, perché è possibile che un programma richieda dati ai descrittori di file 3
, 4
e così via. Infatti, i programmi possono usare qualsiasi numero intero superiore a 2 come nuovi descrittori di file per l’input/output dei dati. Per esempio il seguente codice C legge i dati dal descrittore di file 3
e li replica semplicemente nel descrittore di file 4
:
Note
|
Il programma deve gestire correttamente tali descrittori di file, altrimenti potrebbe tentare un’operazione di lettura o scrittura non valida con conseguente crash applicativo. |
#include <stdio.h> int main(int argc, char **argv){ FILE *fd_3, *fd_4; // Open file descriptor 3 fd_3 = fdopen(3, "r"); // Open file descriptor 4 fd_4 = fdopen(4, "w"); // Read from file descriptor 3 char buf[32]; while ( fgets(buf, 32, fd_3) != NULL ){ // Write to file descriptor 4 fprintf(fd_4, "%s", buf); } // Close both file descriptors fclose(fd_3); fclose(fd_4); }
Per testarlo, salva il codice di esempio come fd.c
e compilalo con gcc -o fd fd.c
. Questo programma richiede che i descrittori di file 3 e 4 siano disponibili in modo da poterli leggere e scrivere. Per esempio, il file precedentemente creato /tmp/error.txt
può essere utilizzato come sorgente per il descrittore di file 3
e il descrittore di file 4
può essere reindirizzato a stdout:
$ ./fd 3</tmp/error.txt 4>&1 cat: /proc/cpu_info: No such file or directory cat: /proc/cpu_info: No such file or directory
Dal punto di vista di un programmatore, l’uso di descrittori di file evita di dover gestire l’analisi delle opzioni e i percorsi del file system. Lo stesso descrittore di file può anche essere utilizzato come input e output. In questo caso, il descrittore di file è definito nella riga di comando con simboli sia minore di che maggiore di, come in 3<>/tmp/error.txt
.
Here Document e Here String
Un altro modo per reindirizzare l’input coinvolge i metodi Here document e Here string. Il reindirizzamento del Here document consente di digitare del testo su più righe che verrà utilizzato come contenuto reindirizzato. Due simboli meno di <<
indicano un reindirizzamento del Here document:
$ wc -c <<EOF > How many characters > in this Here document? > EOF 43
A destra dei due simboli meno di <<
è il termine di fine EOF
. La modalità di inserimento terminerà non appena verrà inserita una riga contenente solo il termine di fine. Qualsiasi altro termine può essere utilizzato come termine di fine, ma è importante non inserire caratteri vuoti tra il simbolo minore di e il termine di fine. Nell’esempio sopra, le due righe di testo sono state inviate allo stdin del comando wc -c
, che mostra il conteggio dei caratteri. Come per i reindirizzamenti di input per i file, viene assunto lo stdin (descrittore di file 0
) se il descrittore di file reindirizzato viene soppresso.
Il metodo Here string è molto simile al metodo Here document
, ma solo per una riga:
$ wc -c <<<"How many characters in this Here string?" 41
In questo esempio, la stringa a destra dei tre segni minore di viene inviata allo stdin di wc -c
, che conta il numero di caratteri. Le stringhe contenenti spazi devono essere racchiuse tra virgolette, altrimenti solo la prima parola verrà utilizzata come Here string
e le restanti verranno passate come argomenti al comando.
Esercizi Guidati
-
Oltre ai file di testo, il comando
cat
può funzionare anche con dati binari, come l’invio del contenuto di un dispositivo a blocchi a un file. Usando il reindirizzamento, come puòcat
inviare il contenuto del dispositivo/dev/sdc
al filesdc.img
nella directory corrente? -
Qual è il nome del canale standard reindirizzato dal comando
date 1> now.txt
? -
Dopo aver provato a sovrascrivere un file usando il reindirizzamento, un utente riceve un errore che informa che l’opzione
noclobber
è abilitata. Come si può disattivare l’opzionenoclobber
per la sessione corrente? -
Quale sarà il risultato del comando
cat <<.>/dev/stdout
?
Esercizi Esplorativi
-
Il comando
cat /proc/cpu_info
mostra un messaggio di errore perché/proc/cpu_info
è inesistente. Il comandocat /proc/cpu_info 2>1
dove reindirizza il messaggio di errore? -
Sarà ancora possibile scartare il contenuto inviato a
/dev/null
se l’opzionenoclobber
è abilitata per la sessione corrente della shell? -
Senza usare
echo
, come potrebbe il contenuto della variabile$USER
essere reindirizzato allo stdin del comandosha1sum
? -
Il kernel Linux mantiene collegamenti simbolici in
/proc/PID/fd/
a ogni file aperto da un processo, dove PID è il numero di identificazione del processo corrispondente. Come potrebbe l’amministratore di sistema utilizzare quella directory per verificare la posizione dei file di log aperti danginx
, supponendo che il suo PID sia1234
? -
È possibile eseguire calcoli aritmetici utilizzando solo i comandi incorporati della shell, ma i calcoli in virgola mobile richiedono programmi specifici, come
bc
(basic calculator). Conbc
è anche possibile specificare il numero di cifre decimali, con il parametroscale
. Tuttavia,bc
accetta operazioni solo tramite il suo standard input, solitamente inserito in modalità interattiva. Usando una Here string, come può l’operazione in virgola mobilescale = 6; 1 / 3
essere inviato allo standard input dibc
?
Sommario
Questa lezione copre i metodi per eseguire un programma reindirizzando i suoi canali di comunicazione standard. I processi Linux utilizzano questi canali standard come descrittori di file generici per leggere e scrivere dati, rendendo possibile modificarli arbitrariamente in file o dispositivi. La lezione tratta i seguenti argomenti:
-
Cosa sono i descrittori di file e il ruolo che svolgono in Linux.
-
I canali di comunicazione standard di ogni processo: stdin, stdout e stderr.
-
Come eseguire correttamente un comando utilizzando il reindirizzamento dei dati, sia per l’input che per l’output.
-
Come utilizzare Here Documents e Here Strings nei reindirizzamenti di input.
I comandi e le procedure trattate erano:
-
Operatori di Reindirizzamento:
>
,<
,>>
,<<
,<<<
. -
Commandi
cat
,set
,uniq
ewc
.
Risposte agli Esercizi Guidati
-
Oltre ai file di testo, il comando
cat
può funzionare anche con dati binari, come l’invio del contenuto di un dispositivo a blocchi a un file. Usando il reindirizzamento, come puòcat
inviare il contenuto del dispositivo/dev/sdc
al filesdc.img
nella directory corrente?$ cat /dev/sdc > sdc.img
-
Qual è il nome del canale standard reindirizzato dal comando
date 1> now.txt
?Standard output o stdout
-
Dopo aver provato a sovrascrivere un file usando il reindirizzamento, un utente riceve un errore che informa che l’opzione
noclobber
è abilitata. Come si può disattivare l’opzionenoclobber
per la sessione corrente?set +C
oset +o noclobber
-
Quale sarà il risultato del comando
cat <<.>/dev/stdout
?Bash entrerà in modalità di immissione Heredoc, quindi uscirà quando un punto appare in una riga da solo. Il testo digitato verrà reindirizzato a stdout (stampato sullo schermo).
Risposte agli Esercizi Esplorativi
-
Il comando
cat /proc/cpu_info
mostra un messaggio di errore perché/proc/cpu_info
è inesistente. Il comandocat /proc/cpu_info 2>1
dove reindirizza il messaggio di errore?A un file chiamato
1
nella directory corrente. -
Sarà ancora possibile scartare il contenuto inviato a
/dev/null
se l’opzionenoclobber
è abilitata per la sessione corrente della shell?Si.
/dev/null
è un file speciale non influenzato danoclobber
. -
Senza usare
echo
, come potrebbe il contenuto della variabile$USER
essere reindirizzato allo stdin del comandosha1sum
?$ sha1sum <<<$USER
-
Il kernel Linux mantiene collegamenti simbolici in
/proc/PID/fd/
a ogni file aperto da un processo, dove PID è il numero di identificazione del processo corrispondente. Come potrebbe l’amministratore di sistema utilizzare quella directory per verificare la posizione dei file di log aperti danginx
, supponendo che il suo PID sia1234
?Eseguendo il comando
ls -l /proc/1234/fd
, che mostrerà le destinazioni di ogni collegamento simbolico nella directory. -
È possibile eseguire calcoli aritmetici utilizzando solo i comandi incorporati della shell, ma i calcoli in virgola mobile richiedono programmi specifici, come
bc
(basic calculator). Conbc
è anche possibile specificare il numero di cifre decimali, con il parametroscale
. Tuttavia,bc
accetta operazioni solo tramite il suo standard input, solitamente inserito in modalità interattiva. Usando una Here string, come può l’operazione in virgola mobilescale = 6; 1 / 3
essere inviato allo standard input dibc
?$ bc <<<"scale=6; 1/3"