Corso di Sistemi Operativi

Caratteristiche avanzate della shell - Parte I

 

Nella scorsa lezione abbiamo introdotto l'interprete dei comandi, ovvero la shell, presentandone alcune funzioni di base.
Sebbene rappresenti un'interfaccia piuttosto ostica per coloro che sono abituati a lavorare in ambienti grafici, tuttavia essa costituisce la soluzione più idonea ed efficace per chi debba lavorare a stretto contatto con il sistema operativo (tipicamente i programmatori), offrendo nondimeno funzionalità interessanti anche per gli utenti comuni.

Abbiamo accennato al comportamento predefinito di molti programmi Unix riguardo la lettura dallo standard input e la scrittura sullo standard output.
Naturalmente, un ambiente di lavoro che si voglia definire personalizzabile (o customizzabile secondo l'attuale terminologia), deve permettere di modificare questo comportamento e, difatti, Unix ha introdotto il concetto di redirezione dello standard input e dello standard output, consistente nella possibilità di indirizzare il flusso dei caratteri in ingresso e/o in uscita da/verso un altro file.

Questa utile funzionalità offerta dalla shell utilizza il carattere '<' (minore) per redirigere lo standard input e il carattere '>' (maggiore) per redirigere lo standard output.
Ad es. il comando:

$ sort < sorgente.txt

prende il suo input dal file 'sorgente.txt' e stampa l'output sullo schermo (lo scopo del programma sort è quello di ordinare alfabeticamente le linee di testo ricevute in input).
Analogamente:

$ sort < sorgente.txt > destinazione.txt

prende il suo input dal file 'sorgente.txt' e scrive l'output sul file 'destinazione.txt'; se quest'ultimo file non esiste viene creato, altrimenti viene sovrascritto.

Molte nuove shell consentono anche di redirigere lo standard output in aggiunta (utilizzando i caratteri '>>') e di redirigere lo standard error (con i caratteri '2>').
Ad es.:

$ sort >> destinazione.txt 2> errori.txt

scrive i messaggi di errore nel file 'errori.txt' e l'output viene accodato al contenuto del file 'destinazione.txt', ovvero se il file esiste non viene sovrascritto, ma gli vengono aggiunti i nuovi dati.

Spesso può presentarsi l'esigenza di utilizzare i dati di output di un programma come input per un altro programma.
Una prima soluzione potrebbe essere quella di utilizzare la redirezione verso/da un file temporaneo da rimuovere successivamente.
Ad es. nella riga:

$ sort < sorgente.txt > temp.txt; head -20 temp.txt; rm -f temp.txt

si è utilizzata la concatenazione di comandi, indicata con il metacarattere ';', per eseguire in successione tre comandi:
1) prendere le righe contenute nel file 'sorgente.txt', ordinarle alfabeticamente e scriverle sul file 'temp.txt';
2) prendere le prime 20 righe del file 'temp.txt' e stamparle sullo standard output;
3) rimuovere il file 'temp.txt' (l'opzione -f forza la cancellazione senza chiedere conferma all'utente).

Notiamo che, in questo esempio, l'esecuzione dei comandi successivi è subordinata al successo dell'esecuzione dell'istruzione precedente.
Infatti se programma sort non va a buon fine il file 'temp.txt' sarà vuoto (o non esisterà affatto), per cui non avrà senso eseguire i programmi seguenti.
Per consentire un controllo più completo sui programmi concatenati, molte shell offrono un operatore di controllo, indicato con '&&', che si comporta come un operatore booleano AND: se il valore di uscita di ciò che sta a sinistra è vero, viene eseguito anche quanto sta a destra.

Quindi scrivendo:

$ sort < sorgente.txt > temp.txt && head -20 temp.txt && rm -f temp.txt

il programma head sarà eseguito se sort terminerà con successo e rm se head sarà terminato con successo.

Per comprendere questo funzionamento, occorre sapere che ogni programma termina con un valore di uscita che viene passato al programma “padre” che lo ha invocato (tipicamente la shell, ma può essere anche un qualsiasi altro programma utente).
In caso di successo, il programma termina passando al “padre” il valore 0, altrimenti un valore diverso da 0 può essere utilizzato dal “padre” per capire la ragione dell'errata terminazione del programma.
Nel nostro esempio head sarà eseguito se e solo se sort terminerà con il valore 0 e rm sarà eseguito se e solo se head sarà terminato con valore 0.

 

Torna all'indice Generale del corso di Corso di Sistemi Operativi di Software Planet