Guida Linux: la shell BASH parte II

I caratteri speciali di completamento dei nomi

Come gia' visto precedentemente per nominare un file e' possibile usare fino a 256 caratteri, pero' esiste una limitazione: non e' possibile usare determinati caratteri. Tali caratteri infatti sono speciali, in quanto se presenti, vengono interpretati dalla shell seguendo delle regole ben precise. Ecco un elenco di alcuni di tali caratteri:

. / " $ & ' ? ~ ! < > * = .. ; [ ]

ognuno di questi caratteri ha un significato ben preciso per la shell, ad esempio il carattere '.' significa la directory corrente, il carattere '..' e' la directory immediatamente superiore, il carattere '~' rappresenta la directory home, il carattere ';' e' usato per separare piu' comandi sulla stessa riga e via dicendo. I caratteri speciali che verranno analizzati qui sono i caratteri: '*', '?' , '[' e ']'. Tali caratteri vengono definiti anche caratteri jolly o anche wildcards. Si tratta di caratteri che vengono usati dalla shell per espandere il nome di un file. Il carattere '*' significa qualsiasi carattere o qualsiasi sequenza di caratteri. Digitando una serie di caratteri e terminando la serie con il carattere *, la shell individuera' tutti i file all'interno della directory corrente i cui nomi iniziano con la serie di caratteri digitati e terminano con una sequenza qualsiasi di caratteri. Digitando solo il carattere *, la shell individuera' semplicemente tutti i file all'interno della directory corrente. Ad esempio, supponiamo che l'utente mau possegga all'interno della directory documenti i file lettera1, lettera2, doc, letteratura.txt, lettere e doc2. Il comando:

ls lett*

visualizzera' solo i file lettera1, lettera2, lettere e letteratura.txt. i file doc1 e doc2 non verranno visualizzati. Cio' perche' la shell considerera' tutti i file presenti all'interno della directory che iniziano con i caratteri 'lett' e terminano con una sequenza qualsiasi di caratteri. I file doc1 e doc2 non soddisfano tali requisiti. Invece, digitando il comando:

ls lettera*

la shell visualizzera' i file lettera1, lettera2 e letteratura.txt. Questa volta, oltre ai file doc1 e doc2 verra' escluso dall'elenco anche il file lettere che percio' non verra' visualizzato. Ma supponiamo ora che di tutti i file presenti nella directory volessimo visualizzare solamente i file lettera1 e lettera2: come dovremmo usare il carattere '*'? Bene, in questo caso scrivendo lettera* visualizzeremmo i file lettera1, lettera2 ma anche letteratura.txt. Come fare allora? Semplice: potremmo usare il carattere '?'. Infatti il carattere ? significa qualsiasi carattere. Nel nostro esempio pertanto potremmo scrivere il comando: 'ls lettera?'. La shell interpretera' la stringa 'lettera?' cercando all'interno della directory corrente tutti i file il cui nome inizia per 'lettera' e termina con 1 carattere qualsiasi. La differenza tra il carattere * ed il carattere ? sta nel fatto che mentre con il primo si intende qualsiasi sequenza di caratteri, con il secondo si intende qualsiasi carattere. Per specificare ulteriormente i caratteri da espandere, si puo' specificare uno o piu' caratteri all'interno di una coppia di parentesi quadre. I caratteri definiti tra parentesi quadre stabiliscono un insieme di caratteri validi che devono essere presenti all'interno del nome dei file da considerare. Ad esempio, supponendo di avere all'interno della directory corrente i file doc1, doc2, docA1, docB1 e doca2, specificando la stringa doc[1A] prenderemmo in considerazione solamente i file doc1 e docA1 in quanto entrambi hanno un nome che inizia con i caratteri doc e termina con il carattere 1 o con il carattere A. Come possiamo osservare non viene preso in considerazione neanche il file doca2 perche' Linux e' un sistema case sensitive, cioe' fa differenza tra caratteri maiuscoli e caratteri minuscoli. Per Linux i caratteri 'A' e 'a' sono due caratteri completamente diversi. Se avessimo voluto prendere in considerazione anche il file doca2, avremmo dovuto scrivere doc[1Aa]. L'ordine con il quale vengono digitati i caratteri jolly all'interno delle parentesi quadre e' ininfluente, percio' avremmo potuto scrivere anche doc[Aa1] o doc[A1a]. Ma i caratteri jolly possono servire non solamente a specificare dei nomi di file che cominciano con una sequenza di caratteri prestabilita e terminano con una sequenza di caratteri indefinita: infatti e' possibile anche effettuare l'operazione inversa, cioe' specificare dei nomi di file che iniziano con una sequenza di caratteri indefinita e che pero' terminano con dei caratteri ben precisi. Ad esempio, supponendo di avere all'interno della directory corrente i file doc.txt, doc.doc, lettera.doc e lettera.txt, scrivendo *.doc specificheremmo solamente i file doc.doc e lettera.doc. All'interno delle parentesi quadre e' possibile anche specificare una sequenza di valori usando il carattere '-'. Ad esempio la stringa doc[1-9] significa qualsiasi file il cui nome inizia per doc e termina con una cifra da 1 a 9. Supponendo di avere all'interno della nostra directory i file doc1, doc2, doc3, doc4 e doc5, scrivendo la stringa doc[1-3] la shell prendera' in considerazione unicamente i file doc1, doc2 e doc3. E' possibile combinare tutti questi caratteri speciali in qualsiasi modo, percio' una stringa del tipo d?c[1-3].* e' perfettamente valida. Supponendo infatti di avere all'interno della nostra directory i file doc1.txt, dic2.txt, dec3.doc, documenti, lettere, fax e moduli, con la stringa d?c[1-2].* prenderemmo in considerazione unicamente i file doc1.txt, dic2.txt e dec3.doc.

Standard input, standard output e standard error

Quando Unix, e di conseguenza anche Linux, quando vennero sviluppati, si volle mantenere indipendenti la struttura logica dei file dalla conformazione del supporto fisico, di conseguenza venne sviluppato il concetto secondo il quale qualsiasi dispositivo fisico puo' essere visto logicamente come un file, ossia come una sequenza continua di byte. Questo concetto logico si estende anche alle operazioni di input ed output, infatti in queste operazioni i dati sono organizzati come sequenze continue di byte. I dati introdotti in input con la tastiera vengono inseriti all'interno di un canale costituito da una sequenza continua di byte. Allo stesso modo i dati prodotti a video vengoni inseriti all'interno di un altro canale. Tali canali vengono definiti standard input e standard output. Pertanto la tastiera e' il canale standard input ed il video e' il canale standard output. Qualsiasi comando quindi, accetta in input dei valori che legge dallo standard input (la tastiera) e produce dei risultati scrivendoli nello standard output (il video). Ma un comando puo' produrre anche dei messaggi di errore se per esempio vengono introdotti dei valori in input non validi. I messaggi di errore dei comandi vengono scritti in un terzo canale, lo standard error. Lo standard error generalmente coincide con lo standard output, nel senso che sia il risultato di un comando che eventuali errori vengono visualizzati a video. Digitando il comando cat pippo, otterremo a video il contenuto del file pippo, in quanto cat accetta dallo standard input (la tastiera) l'argomento pippo e lo invia allo standard output (il video). Cosa accade pero' se si digita cat senza argomenti e si preme il tasto invio? Verra' eseguito il comando cat che leggera' lo standard input. In pratica ěl comando cat accetta da tastiera degli argomenti. A questo modo e' possibile scrivere un documento come una lettera ad esempio. Per terminare la scrittura della lettera occorre premere la combinazione di tasti CTRL-D. Tale combinazione di tasti corrisponde infatti al carattere di fine file (EOF, cioe' End Of File). Infatti lo standard input e' un file come un altro. Usando CTRL-D scriviamo il carattere di fine file ed il comando cat smettera' di leggere cio' che digitiamo. Questi 3 canali sono dei file ben distinti e separati, e questo e' un concetto importante da tenere a mente, poiche' Linux (cosi' come Unix) ci consente di redirigere un canale standard da o verso un file. E' possibile ad esempio inviare l'output prodotto da un comando non a video (il canale standard output) ma all'interno di un file. Oppure e' possibile far si che un comando accetti in input dei valori prendendoli da un file piuttosto che dalla tastiera. Queste operazioni di redirezione vengono effettuate utilizzando gli operatori di redirezione '<', '>' e '>>'. Il primo e' l'operatore di redirezione dell'input standard, mentre gli ultimi due sono gli operatori di redirezione dell'output standard. Supponiamo che digitando il comando ls il sistema produca a video la seguente lista di file:

pippo
pluto
topolino
minnie

supponiamo ora di voler conservare questo elenco di file all'interno di un documento chiamato disney.txt. Bene, per eseguire tale operazione dovremmo redirigere l'output standard (il video) all'interno del file disney.txt tramite l'operatore '>' in questo modo:

ls > disney.txt

eseguendo tale comando la shell interpretera' l'operatore '>' redirigendo il risultato del comando ls all'interno del file disney.txt. In altre parole tale comando fornisce le seguenti istruzioni per la shell: 'esegui il comando ls ma non inviare il risultato a video perche' lo devi inviare all'interno del file disney.txt; se tale file non esiste crealo'. Cosi' la shell creera' il file disney.txt ed inviera' l'output del comando ls all'interno di tale file. Qualora il file disney.txt fosse gia' presente, la shell lo creera' nuovamente, distruggendo eventuali dati gia' presenti. Nel nostro esempio il comando ls > disney.txt creera' il file disney.txt scrivendo all' interno i seguenti valori:

pippo
pluto
topolino
minnie
disney.txt

per visualizzare il contenuto del file disney.txt potremmo utilizzare il comando cat:

cat disney.txt
pippo
pluto
topolino
minnie
disney.txt

Come possiamo notare all'interno del file disney.txt e' presente anche il nome disney.txt. Infatti con l'operatore > la shell prima crea il file disney.txt e successivamente esegue il comando ls (che elenchera' anche il file appena creato). Supponiamo ora di cancellare i file pluto topolino e minnie dalla nostra directory e di creare un file chiamato paperino.

ls (elenca i file della directory)
pippo
pluto
topolino
minnie
disney.txt
ls > disney.txt (reindirizza il risultato del comando ls nel file disney.txt)
cat disney.txt (visualizza il contenuto del file disney.txt)
pippo
pluto
topolino
minnie
disney.txt
rm pluto topolino minnie (cancella i file pluto topolino e minnie)
ls (visualizza il contenuto della directory dove ora sono presenti solo i file pippo e disney.txt)
pippo
disney.txt
cp pippo paperino (copia pippo in paperino, cioe' crea il file paperino che e' una copia di pippo)
ls (visualizza il contenuto della directory che ora contiene i file pippo, paperino e disney.txt)
pippo
paperino
disney.txt
ls > disney.txt (reindirizza il risultato del comando ls nel file disney.txt distruggendo cio' che conteneva precedentemente)
cat disney.txt (infatti visualizzando il file disney.txt vedremo che pluto, topolino e minnie non sono piu' presenti)
pippo
paperino
disney.txt

Come abbiamo visto, eseguendo nuovamente il comando ls > disney.txt il contenuto precedente del file disney.txt viene azzerato e vengono scritti all'interno solo i nomi pippo e paperino. Come fare per aggiornare il file disney.txt senza distruggere il contenuto precedente? Potremmo usare l'operatore di redirezione dello standard output '>>'. Infatti tale operatore non distrugge il file, in quanto permette di accodare alla fine del file il risultato prodotto dal comando. Tornando al nostro esempio eseguendo il comando ls per la seconda volta ma utilizzando l'operatore >> al posto dell'operatore > il contenuto del file non verrebbe cancellato in quanto il risultato del comando ls verrebbe accodato ad esso. Percio' eseguendo il comando ls >> disney.txt si otterrebbe un file disney.txt contenente i nomi: pippo, pluto, topolino, minnie, pippo e paperino. Come si puo' osservare pippo e' ripetuto due volte in quanto il contenuto del file non e' stato cancellato. Ovviamente per utilizzare il comando ls >> disney.txt occorre che il file disney.txt sia esistente, in caso contrario otterremmo un errorre dalla shell. Infatti mentre l'operatore '>' crea un nuovo file, l'operatore '>>' accoda all'interno di un file gia' esistente. L'operazione di redirezione puo' avvenire anche all'inverso, in quanto e' possibile redirigere il canale di input standard. Generalmente i comandi accettano dei valori leggendoli dal canale di input standard cioe' dalla tastiera. Per esempio il comando:

ls /home/mau/documenti

visualizza il contenuto della directory /home/mau/documenti. Tale directory e' un argomento che abbiamo fornito noi in input digitandolo da tastiera. E' possibile pero' fare in modo che il comando ls prenda in input l'argomento '/home/mau/documenti' non da tastiera ma ad esempio da un file. Cio' puo' essere fatto redirigendo l'input standard, cioe' copiando il contenuto di un file all'interno del canale di input standard (ricordiamo che in Linux la struttura fisica dei dispositivi e' separata dalla struttura logica dei file, pertanto un comando sa che deve accettare eventuali argomenti dal canale di input standard ignorando completamente se tale canale sia la tastiera, il disco o qualsiasi altro supporto). Ad esempio il comando:

ls < pippo

redirige il contenuto del file pippo nell'input standard. Come gia' accennato, ogni volta che viene eseguito un comando la shell si occupa di collegare input standard ed output standard al comando stesso: interpretando il comando, in questo caso la shell collega l'output standard e l'input standard ma prima di far cio' redirige il contenuto del file pippo all'interno dell'input standard. Percio' se all'interno del file e' presente la stringa '/home/mau/documenti', tale stringa verra' copiata dalla shell (cioe' rediretta) nel canale di input standard. Quando il comando ls leggera' l'input standard, trovera' quindi all'interno la stringa '/home/mau/documenti' appena copiata dalla shell. E' possibile redirigere l'input e l'output standard contemporaneamente, infatti il comando:

cat < pippo > pluto

legge dal file pippo e scrive il risultato nel file pluto.

Le pipe

Spesso puo' essere utile inviare l'output di un comando non a video ma ad un altro comando prima di essere visualizzato. Supponiamo ad esempio di voler visualizzare l'elenco dei file contenuti all'interno di una directory. Supponiamo anche che il risultato prodotto sia un elenco interminabile di file. E possibile in questo caso utilizzare il comando more che accetta in input dei dati e li visualizza a video sotto forma di pagine formattate, consentendo la visualizzazione di una pagina per volta. Premendo un tasto qualsiasi il comando more visualizza la pagina successiva. Come e' possibile collegare l'output prodotto dal comando ls al comando more? E' possibile utilizzando l'operatore di pipe '|'. E' il carattere che si trova nel tasto posto sotto al tasto esc. Si ottiene premendolo contemporaneamente al tasto shift (il tasto che permette di scrivere un carattere maiuscolo). Usando l'operatore di pipe '|' comunichiamo alla shell che e' necessario collegare l'output standard del primo comando all'input standard del secondo comando. Ad esempio il comando:

ls | more

invia il risultato del comando ls al comando more. Il comando more a sua volta formatta tale risultato e lo invia a video. E' possibile usare il comando less al posto del comando more, in quanto tale comando permette di scorrere le pagine avanti ed indietro (less e' in sostanza una versione migliorata del comando more). Un'altra cosa che Linux permette di fare e' consentire ad un comando di accettare degli argomenti sia dall'input standard e sia da un file. Redirigere l'input standard con l'operatore < significa in pratica copiare dei dati da un file all'interno dell'input standard. Puo' essere utile pero' far si che un comando accetti degli argomenti dall'input standard e contemporaneamente da un file. E' possibile farlo utilizzando l'operatore '-'. L'operatore '-' rappresenta infatti l'input standard. Vediamo un esempio concreto. Supponiamo di voler visualizzare il contenuto di un file a video usando il comando cat. Supponiamo anche di voler visualizzare prima del contenuto del file anche il nome della directory corrente che lo contiene. Il nome della directory corrente si ottiene con il comando pwd (Print Working Directory, cioe' stampa la directory di lavoro). Potremmo scrivere percio':

pwd | cat - miofile

cosa significano questi comandi? Il comando pwd crea in output il nome della directory, supponiamo /home/mau ma invece di visualizzarlo a video lo invia tramite l'operatore di pipe '|' al comando cat. Cio' accade perche' la shell interpretando la riga comandi, nota l'operatore di pipe '|' e quindi collega l'output standard del comando pwd all'input standard del comando cat. Il comando cat quindi leggera' dall'input standard la riga prodotta da pwd (/home/mau) ma anche il nome del file miofile (miofile e' stato digitato con la tastiera pertanto si trova all'interno dell'input standard). In altre parole il comando cat visualizzera' prima il primo argomento letto dall'input standard, cioe' il nome della directory prodotto dal comando pwd e successivamente il secondo argomento letto dall'input standard, cioe' il file miofile. Il risultato finale sara' il nome della directory ed il contenuto del file prodotti a video. Cosi' come e' possibile forzare un comando ad accettare un argomento dall'input standard ed un altro da un file e' anche possibile l'operazione inversa. E' possibile cioe' inviare il risultato di un comando sia a video (output standard) che in un file. Cio' e' possibile utilizzando il comando tee. Il comando cat pippo visualizza a video il contenuto del file pippo. Per visualizzarne il contenuto e contemporaneamente scriverlo all'interno di un altro file, si puo usare il comando tee in questo modo:

cat pippo | tee pluto

il comando cat legge il contenuto del file pippo e lo invia allo standard output. La shell pero' notando l'operatore di pipe '|' collega l'output standard del comando cat all'input standard del comando tee. Il comando tee a sua volta legge il contenuto del file pippo dal suo input standard e lo invia sia a video che all'interno del file pluto. Vediamo a questo punto come redirigere l'ultimo canale standard visto: il canale error standard. Quando un comando viene eseguito, normalmente viene prodotto un risultato a video. Se pero' sbagliamo qualcosa nel digitare il comando, viene prodotto a video un messaggio di errore. Supponiamo ad esempio di voler visualizzare il contenuto del file pippo ma digitando erroneamente scriviamo:

cat peppo

poiche' il file peppo non esiste, il comando cat visualizzera' a video il messaggio di errore cat: peppo not found. Infatti normalmente il canale di standard error e' il video. Come fare per scrivere il messaggio di errore non a video ma all'interno di un file? Ogni canale standard e' identificabile da un numero: 0 per il canale standard input, 1 per il canale standard output e 2 per il canale standard error. Digitare il comando cat peppo > errori non produrrebbe il risultato voluto in quanto l'operatore > redirige lo standard output all'interno del file errori ma non lo standard error. Poiche' il file peppo non esiste il comando cat non scrive nulla nello standard output ma scrive un messaggio di errore nello standard error. Per specificare quale canale redirigere nel file errori si puo' usare il numero che lo identifica. Nel nostro esempio desideriamo redirigere lo standard error (2) e non lo standard output (1) all'interno del file errori. Pertanto possiamo scrivere:

cat peppo 2> errori

Il numero 2 a sinistra dell'operatore > specifica che il canale che intendiamo redirigere non e' lo standard output ma bensi' lo standard error. Il comando cat pippo > pluto scrive il contenuto di pippo all'interno di pluto. Questo perche' per default l'operatore > redirige lo standard output. In pratica e' la stessa cosa che scrivere cat pippo 1> pluto, in quanto in tal caso 1 se non specificato e' sottinteso. Diverso e' il comando 'cat pippo 1> dati 2> errori'. Qui si vuole infatti specificare che occorre inviare il contenuto di pippo all'interno del file dati ed eventuali errori all'interno del file errori. Tanto per complicare un po' di piu' le idee, illustriamo come sia possibile redirigere un canale standard all'interno di un altro canale standard. Fino ad ora abbiamo infatti rediretto un canale standard verso un file o viceversa, un file verso un canale standard. Per far riferimento ad un canale standard occorre usare l'operatore &. Infatto &0 fa riferimento al canale standard input, &1 fa riferimento al canale standard output e &2 fa riferimento al canale standard error. Quindi la stringa '2>&1' significa: redirezione del canale standard error (2) nel canale standard output (&1). Vediamo ad esempio il comando:

cat non_esiste 1> dati 2>&1

tale comando visualizza il contenuto del file non_esiste inviandolo non a video ma all'interno del file dati ed inoltre invia eventuali errori all'interno dello stesso file. In questo caso poiche' il file non_esiste come dice il nome non esiste ;o) verra' prodotto un messaggio di errore. Analizziamo il comando: cat legge dallo standard input il nome del file da visualizzare ma poiche' non lo trova produce un errore; inoltre il comando cat sa che il contenuto di tale file dovrebbe essere inviato all'interno del file dati e non a video ('1>' infatti redirige lo standard output nel file dati); infine cat sa che lo standard error deve essere rediretto nello standard output ('2>&1' infatti redirige lo standard error nello standard output). Il risultato e' che il messaggio di errore andrebbe scritto nello standard error ma, poiche' tale canale e' stato rediretto, viene scritto nello standard output. Poiche a sua volta lo standard output e' stato rediretto nel file dati, il messaggio di errore verra' scritto nel file dati. Seguendo lo stesso percorso logico, la stringa '1>&2' redirige lo standard output verso lo standard error. Riassumendo, '2>&1' invia lo standard error verso lo standard output e 1>&2 produce il risultato contrario.

Variabili d'ambiente

Una variabile e' una parte della memoria RAM identificata da un nome che puo' contenere dei valori. E' una scatola nera, un contenitore all'interno del quale possiamo collocare una data, un nome, una cifra e cosi' via. Quando viene definita una nuova variabile, il sistema associa al nome di tale variabile un indirizzo di memoria RAM a partire dal quale viene memorizzato un valore stabilito dall'utente. Per definire e valorizzare una variabile e' sufficiente assegnare un valore ad un nome, ad esempio, il comando:

PIPPO=253

definisce una variabile di nome PIPPO ed assegna a questa variabile il valore '253'. In altre parole il sistema alloca uno spazio di memoria RAM a partire da un indirizzo scelto da lui (ad esempio 12234) una zona all'interno della quale memorizza il valore 253. Cio' significa che la cella di memoria 12234 contiene 2, la cella contigua 12235 contiene 5 e la cella contigua 12236 contiene 3. Queste 3 celle contigue rappresentano una entita' di nome PIPPO. Oltre a contenere valori numerici, una variabile puo' contenere anche stringhe, cioe' insiemi di caratteri. Ad esempio il comando PIPPO=scatola, crea una variabile di nome PIPPO all'interno della quale viene memorizzato la stringa 'scatola'. Molte variabili contengono dei valori utili al sistema. Ad esempio la variabile USERNAME contiene il nome dell'utente che si e' collegato al sistema mentre la variabile HOME contiene il path della directory home dell'utente (ad esempio /home/mau). Una stringa puo' contenere anche il carattere spazio, ma in questo caso occorre racchiuderla tra doppi apici. Ad esempio il comando MIAVAR="ciao a tutti" crea una variabile di nome MIOVAR e ne memorizza all'interno la stringa "ciao a tutti". Il carattere '=' rappresenta l'operatore di assegnamento, cioe' l'operatore che assegna il valore alla variabile. Tra il nome della variabile, l'operatore '=' ed il valore vero e proprio non devono essere presenti spazi. Quindi il comando MIAVAR = 234 non e' corretto, perche' sono presenti degli spazi. Invece il comando MIAVAR=234 e' un comando corretto. Una variabile ha vita solo all'interno della shell nella quale viene creata, pertanto cambiando shell, il sistema non riconosce piu' tale variabile. Come sappiamo e' possibile creare delle subshell, cioe' delle shell all'interno di altre shell. Bene, se definiamo la variabile PIPPO all'interno di una data shell e successivamente apriamo una seconda shell, la variabile PIPPO rimarra' sconosciuta alla seconda shell. Possiamo verificarlo con questa sequenza di comandi:

PIPPO=maurizio (definisco una variabile di nome PIPPO che contiene la stringa 'maurizio')
set (il comando set visualizza tutte le variabili definite: mostrera' anche la variabile PIPPO)
bash (creo una subshell bash)
set (visualizzo le variabili definite e, con sorpresa, non trovo piu' la variabile PIPPO)
exit (o CTRL-D, con questo comando esco dalla subshell e torno alla shell principale)
set (ripeto il comando set ed ora la variabile PIPPO e' nuovamente visibile)

Affinche' una variabile sia visibile all'interno di qualsiasi shell, occorre 'esportarla' mediante il comando export. Ad esempio:

PIPPO="ciao a tutti"
export PIPPO (ora la variabile PIPPO e' visibile da qualsiasi shell)

Per visualizzare le variabili definite si puo' usare il comando set, mentre per visualizzare le variabili di ambiente occorre usare il comando env. Le variabili di ambiente sono tutte quelle variabili predefinite all'interno della shell che troviamo normalmente all'interno di un sistema Linux. Per visualizzare l'elenco di tali variabili usiamo il comando env:

env

Per visualizzare il contenuto di una variabile invece, occorre usare il comando echo insieme all'operatore '$'. L'operatore $ serve per far riferimento al contenuto di una variabile. Ad esempio il comando:

echo $PIPPO

visualizza a video il contenuto della variabile PIPPO.

Comandi eseguiti in background

I programmi che sono in esecuzione sotto Linux vengono definiti processi. Quando si esegue un comando come ad esempio ls, viene messo in esecuzione un processo. Ogni processo sotto Linux viene identificato da un numero univoco: il PID. PID sta per Process IDentifier cioe' identificatore del processo. A dire il vero i comandi eseguiti dagli utenti vengono definiti job. Si tratta sempre di processi, ma i processi utente vengono definiti job per distinguerli dai processi di sistema. Un comando, come qualsiasi processo puo' essere eseguito in background (lett. in sottofondo) nel senso che mentre il comando e' in esecuzione l'utente puo' eseguire altre attivita'. E' conveniente eseguire un comando in background quando la sua esecuzione richiede del tempo. Ad esempio la ricerca di un file all'interno di un grosso disco scorrendo tutte le directory richiede un po' di tempo: e' possibile eseguire tale ricerca in background e nel frattempo eseguire altre attivita'. Per eseguire un comando in background e' sufficiente apporre il carattere di e commerciale '&' alla fine del comando. Ad esempio per stampare un file molto grande si puo' lanciare il comando lpr in questo modo:

lpr dati &
[1] 534

il carattere & permette di eseguire il comando lpr in background, permettendoci di eseguire altre attivita' evitando di dover aspettare che il comando termini la sua esecuzione. La riga presente sotto a quella che contiene il comando rappresenta il numero del job (1) ed il PID del processo (%34). Cio' significa che il comando lpr appena lanciato e' identificato dal sistema come processo numero 534 e job numero 1. E' possibile eseguire in background piu' di un comando contemporaneamente. Per visualizzare i comandi in esecuzione in background (cioe' i job) si utilizza il comando jobs.

jobs
[1] + running lpr dati
[2] - running cat *.txt > testo

Il comando jobs visualizza i comandi in esecuzione in background e per ogni comando viene indicato il numero del job, lo stato del comando (running o stopped) ed il comando stesso. Un comando in stato running e' un comando in esecuzione mentre un comando in stato stopped e' un comando fermo. Il carattere + indica il job corrente, cioe' quello attualmente in esecuzione, mentre il carattere - indica il prossimo job che verra' eseguito. Non bisogna confondere un job stopped da uno non ancora in esecuzione: il primo e' un job fermo in attesa di essere riattivato o ucciso, il secondo e' un job attivo ma non ancora in esecuzione. Questa distinzione e' importante perche' l'utente puo' spospendere un job e riattivarlo in qualsiasi momento. E' possibile eseguire piu' comandi in background digitandoli sulla stessa riga e terminandoli con il carattere &:

lpr dati & cat *.txt > testo &
[1] 534
[2] 567

Linux avverte della conclusione di job solo quando si termina il comando corrente (ad esempio una sessione di editing in vi). Per essere avvertiti della conclusione di un job si puo' utilizzare il comando notify. Usando il comando notify, non appena un job termina Linux interrompe il comando corrente (indipendentemente dall'operazione che si sta svolgendo) avvertendo l'utente della conclusione del job. Il comando notify accetta come parametro il numero del job che desideriamo tenere sotto controllo. Nell'esempio precedente, digitando il comando notify %1 Linux avvisera' l'utente - interrompendo qualsiasi azione stia facendo - non appena il comando 'lpr dati' (il job numero 1) sara' terminato. E' possibile portare un comando da modalita' background a modalita' foreground (la normale modalita' di esecuzione dei comandi) utilizzando il comando fg. E' anche possibile l'operazione opposta, cioe' da foreground a background mediante il comando bg. E' possibile annullare l'esecuzione di un comando mediante il comando kill (lett. uccidi, uccidere). Nell'esempio precedente il comando kill %2 annullera' l'esecuzione del job numero 2 ossia del comando 'cat *.txt > testo'. E' possibile annullare un comando indicando il numero del job od il numero del processo cioe' il PID. E' possibile anche sospendere temporaneamente un comando senza ucciderlo definitivamente premendo la combinazione di tasti CTRL-Z. L'utente puo' riattivare il comando un secondo tempo in modalita' background o foreground mediante i comandi bg e fg. Tutto cio' puo' essere utile nei casi in cui l'esecuzione di un comando appena digitato richieda piu' tempo del previsto. In questo caso e' possibile mettere in background il comando, ma occorre prima di tutto sospenderne l'esecuzione premendo i tasti CTR-Z. Non e' possibile infatti mettere il comando in background direttamente senza averne prima sospeso l'esecuzione. Una volta sospesa l'esecuzione del comando, lo si puo' mettere in backgroun usando il comando bg:

lpr divinacommedia.txt (stampo tutta la divina commedia ;o)
CTRL-Z (sospendo l'esecuzione del comando non appena mi accorgo che il comando richiede molto tempo)
jobs
[1] 345 + stopped lpr divinacommedia.txt
bg %1 (metto in background il comando di stampa)

 

Torna all'indice

Copyright (c) 2002 M. Silvestri