[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home] [volume] [parte]


Capitolo 144.   Shell POSIX: programmazione

La programmazione con una shell POSIX implica la realizzazione di file script. Alcune istruzioni sono particolarmente utili nella realizzazione di questi programmi, anche se non sono necessariamente utilizzabili solo in questa circostanza.

144.1   Caratteristiche di uno script

Nei sistemi Unix esiste una convenzione attraverso la quale si automatizza l'esecuzione dei file script. Prima di tutto, uno script è un normalissimo file di testo contenente una serie di istruzioni che possono essere eseguite attraverso un interprete. Per eseguire uno script occorre quindi avviare il programma interprete e informarlo di quale script questo deve eseguire. Per esempio, il comando seguente avvia l'eseguibile sh come interprete dello script pippo, ovvero il file pippo collocato nella directory corrente:

sh pippo[Invio]

Per evitare questa trafila, si può dichiarare all'inizio del file script il programma che deve occuparsi di interpretarlo. Per questo si usa la sintassi seguente:

#! percorso_del_programma_interprete

Quindi, si attribuisce a questo file il permesso di esecuzione:

chmod +x pippo[Invio]

Quando si tenta di avviare questo file come se si trattasse di un programma, il sistema avvia in realtà l'interprete.

Perché tutto possa funzionare, è necessario che il programma indicato nella prima riga dello script sia raggiungibile così come è stato indicato, cioè sia provvisto del percorso necessario. Per esempio, nel caso di uno script per la shell sh (/bin/sh), la prima riga deve essere composta così:

#!/bin/sh
...
...

Il motivo per il quale si utilizza il simbolo # iniziale, è quello di permettere ancora l'utilizzo dello script nel modo normale, come argomento del programma interprete: rappresentando un commento non interferisce con il resto delle istruzioni.

Come appena accennato, il simbolo # introduce un commento che termina alla fine della riga, cioè qualcosa che non ha alcun valore per l'interprete; inoltre, le righe vuote e quelle bianche vengono ignorate nello stesso modo.

144.2   Strutture

Per la formulazione di comandi complessi si possono usare le strutture di controllo e di iterazione tipiche dei linguaggi di programmazione più comuni. Queste strutture sono particolarmente indicate per la preparazione di script di shell, ma possono essere usate anche nella riga di comando di una shell interattiva.

È importante ricordare che il punto e virgola singolo (;) viene utilizzato per indicare una separazione e può essere rimpiazzato da uno o più codici di interruzione di riga.

144.2.1   for

Il comando for esegue una scansione di elementi e in corrispondenza di questi esegue una lista di comandi.

for variabile [in valore...]
do
    lista_di_comandi
done

L'elenco di parole che segue la sigla in viene espanso, generando una lista di elementi; la variabile indicata dopo for viene posta, di volta in volta, al valore di ciascun elemento di questa lista; infine, la lista di comandi che segue do viene eseguita ogni volta (una volta per ogni valore disponibile). Se la sigla in (e i suoi argomenti) viene omessa, il comando for esegue la lista di comandi (do) una volta per ogni parametro posizionale esistente. In pratica è come se venisse usato: in $@.

Il valore restituito da for è quello dell'ultimo comando eseguito all'interno della lista do, oppure zero se nessun comando è stato eseguito.

L'esempio seguente mostra uno script che, una volta eseguito, emette in sequenza gli argomenti che gli sono stati forniti:

#!/bin/sh
for i in $@
do
    echo $i
done

L'esempio seguente mostra uno script un po' più complicato che si occupa di archiviare, singolarmente, i file e le directory che si mettono come argomenti:

#!/bin/sh
ELENCO_DA_ARCHIVIARE=$@
for DA_ARCHIVIARE in $ELENCO_DA_ARCHIVIARE
do
    tar czvf ${DA_ARCHIVIARE}.tgz $DA_ARCHIVIARE
done

144.2.2   case

Il comando case permette di eseguire una scelta nell'esecuzione di varie liste di comandi. La scelta viene fatta confrontando una parola (di solito una variabile) con una serie di modelli. Se viene trovata una corrispondenza con uno dei modelli, la lista di comandi relativa viene eseguita.

case parola in
    [modello [ | modello]... ) lista_di_comandi ;; ]
    ...    
    [*) lista_di_comandi ;; ]
esac

La parola che segue case viene espansa e quindi confrontata con ognuno dei modelli, usando le stesse regole dell'espansione di percorso (i nomi dei file). La barra verticale (|) viene usata per separare i modelli quando questi rappresentano possibilità diverse di un'unica scelta.

Quando viene trovata una corrispondenza, viene eseguita la lista di comandi corrispondente. Dopo il primo confronto riuscito, non ne vengono controllati altri dei successivi. L'ultimo modello può essere *), corrispondente a qualunque valore, che si può usare come alternativa finale in mancanza di altro.

L'esempio seguente mostra uno script che fa apparire un messaggio diverso a seconda dell'argomento fornitogli:

#!/bin/sh
case $1 in
    -a | -A | --alpha)    echo "alpha"    ;;
    -b)                   echo "bravo"    ;;
    -c)                   echo "charlie"  ;;
    *)                    echo "opzione sconosciuta" ;;
esac

Come si può notare, per selezionare alpha si possono utilizzare tre opzioni diverse.

144.2.3   if

Il comando if permette di eseguire liste di comandi differenti, in funzione di una o più condizioni, espresse anch'esse in forma di lista di comandi.

if lista_condizione
then
    lista_di_comandi
[elif lista_condizione
then
    lista_di_comandi]
...
[else
    lista_di_comandi]
fi

Inizialmente viene eseguita la lista che segue if che costituisce la condizione. Se il valore restituito da questa lista è zero (cioè Vero), allora viene eseguita la lista seguente then e il comando termina. Altrimenti viene eseguita ogni elif in sequenza, fino a che ne viene trovata una la cui condizione si verifica. Se nessuna condizione si verifica, viene eseguita la lista che segue else, sempre che esista.

L'esempio seguente mostra uno script che fa apparire un messaggio di avvertimento se non è stato utilizzato alcun argomento, altrimenti si limita a visualizzarli:

#!/bin/sh
if [ $# = 0 ]
then
    echo "devi fornire almeno un argomento"
else
    echo $@
fi

L'esempio seguente mostra uno script attraverso il quale si tenta di creare una directory e se l'operazione fallisce viene emessa una segnalazione di errore:

#!/bin/sh
if ! mkdir deposito
then
    echo "Non è stato possibile creare la directory \"deposito\""
else
    echo "È stata creata la directory \"deposito\""
fi

È importante comprendere subito che le parentesi quadre sono un sinonimo del comando test e come tali devono essere distaccate da ciò che appare prima e dopo. Il comando test viene descritto nella sezione 144.4 e la tabella 144.14 riporta le espressioni che con questo comando possono essere valutate.

144.2.4   while

Il comando while permette di eseguire un gruppo di comandi in modo ripetitivo mentre una certa condizione continua a dare il risultato Vero.

while lista_condizione
do
    lista_di_comandi
done

Il comando while esegue ripetitivamente la lista che segue do finché la lista che rappresenta la condizione continua a restituire il valore zero (Vero).

Lo script dell'esempio seguente contiene un ciclo perpetuo, in cui viene richiesto di inserire qualcosa, ma solo se si inserisce la stringa fine si conclude l'iterazione:

#!/bin/sh
RISPOSTA="continua"
while [ "$RISPOSTA" != "fine" ]
do
    echo "usa la parola fine per terminare"
    read RISPOSTA
done

144.2.5   until

Il comando until permette di eseguire un gruppo di comandi in modo ripetitivo mentre una certa condizione continua a dare il risultato Falso.

until lista_condizione
do
    lista_di_comandi
done

Il comando until è analogo a while, cambia solo l'interpretazione della lista che rappresenta la condizione nel senso che il risultato di questa viene invertito (negazione logica). In generale, per avere maggiori garanzie di compatibilità conviene utilizzare solo il comando while, invertendo opportunamente la condizione.

144.2.6   Funzioni

Attraverso le funzioni è possibile dare un nome a un gruppo di comandi, in modo da poterlo richiamare come si fa per un comando interno normale. Sotto questo aspetto, le funzioni vengono impiegate normalmente all'interno di file script.

[function] nome () {
    lista_di_comandi
}

Le funzioni vengono eseguite nel contesto della shell corrente e quindi non vengono attivati altri processi per la loro interpretazione (ciò al contrario di quanto capita quando viene avviata l'interpretazione di un nuovo script).

La lista di comandi viene eseguita ogni volta che il nome della funzione è utilizzato come comando. Il valore restituito dalla funzione è quello dell'ultimo comando a essere eseguito all'interno di questa.

Pertanto, la funzione della shell può restituire solo un valore di uscita (exit status).

Quando viene eseguita una funzione, i parametri posizionali contengono gli argomenti di questa funzione e anche # restituisce un valore corrispondente alla situazione. Tuttavia, il parametro posizionale zero continua a restituire il valore precedente, di solito il nome dello script.

All'interno della funzione possono essere dichiarate delle variabili locali attraverso il comando interno typeset.

Il comando interno typeset ha molte funzionalità che dipendono da opzioni particolari e probabilmente esistono altri comandi più specifici per la creazione di variabili locali all'interno delle funzioni. Tuttavia, in situazioni in cui si vuole scrivere codice compatibile tra shell POSIX diverse, può essere più conveniente l'uso del comando typeset (senza specificare opzioni).

È possibile utilizzare il comando interno return per concludere anticipatamente l'esecuzione della funzione. Al termine dell'esecuzione della funzione, i parametri posizionali riprendono il loro contenuto precedente e l'esecuzione dello script riprende dal comando seguente alla chiamata della funzione.

Se la shell lo consente, le funzioni possono essere esportate e rese disponibili a una subshell utilizzando il comando interno export, così come si fa per le variabili di ambiente.

L'esempio seguente mostra uno script che prima dichiara una funzione denominata messaggio e subito dopo la esegue semplicemente nominandola come un comando qualsiasi:

#!/bin/sh
messaggio () {
    echo "ciao,"
    echo "bella giornata vero?"
}

messaggio

Nell'esempio seguente, una funzione si occupa di emettere il riepilogo della sintassi per l'uso di un ipotetico script:

function sintassi () {
    echo "al {--latex | --html | --txt | --check}"
    echo ""
    echo "--latex    esegue la conversione in latex;"
    echo "--html     esegue la conversione in html;"
    echo "--txt      esegue la conversione in testo normale;"
    echo "--check    esegue il controllo sintattico SGML;"
}

Nell'esempio seguente, si utilizza il comando return per fare in modo che l'esecuzione della funzione termini in un punto determinato restituendo un valore stabilito. Lo scopo dello script è quello di verificare che esista il file pippo nella directory /var/log/packages/:

#!/bin/sh
function verifica() {
    if [ -e "/var/log/packages/$1" ]
    then
        return 0
    else
        return 1
    fi
}

if verifica pippo
then
    echo "il pacchetto pippo esiste"
else
    echo "il pacchetto pippo non esiste"
fi      

144.3   Espressioni aritmetiche

La shell consente di risolvere delle espressioni aritmetiche in certe circostanze. In generale, nella maggior parte delle shell per le quali si dichiara la compatibilità POSIX, si ottiene l'espansione di un'espressione aritmetica con la forma seguente:

$((espressione))

Il calcolo avviene su interi senza controllo dello straripamento (overflow), anche se normalmente la divisione per zero viene intercettata e segnalata come errore. Oltre alle espressioni puramente aritmetiche si possono risolvere espressioni logiche e binarie, anche se l'utilizzo di queste ultime non è indicato. La tabella 144.11 riporta l'elenco degli operatori aritmetici disponibili.

Tabella 144.11. Operatori aritmetici.

Operatore e
operandi
Descrizione
+op
Non ha alcun effetto.
-op
Inverte il segno dell'operando.
op1 + op2
Somma i due operandi.
op1 - op2
Sottrae dal primo il secondo operando.
op1 * op2
Moltiplica i due operandi.
op1 / op2
Divide il primo operando per il secondo.
op1 % op2
Modulo: il resto della divisione tra il primo e il secondo operando.
var = valore
Assegna alla variabile il valore alla destra.
op1 += op2
op1 = op1 + op2
op1 -= op2
op1 = op1 - op2
op1 *= op2
op1 = op1 * op2
op1 /= op2
op1 = op1 / op2
op1 %= op2
op1 = op1 % op2

Le variabili di shell possono essere utilizzate come operandi; l'espansione di parametri e variabili avviene prima della risoluzione delle espressioni. Quando una variabile o un parametro vengono utilizzati all'interno di un'espressione, vengono convertiti in interi. Una variabile di shell non ha bisogno di essere convertita.

Gli operatori sono valutati in ordine di precedenza. Le sottoespressioni tra parentesi sono risolte prima.

144.4   Comandi interni

I comandi interni sono quelli eseguiti direttamente dalla shell, come se si trattasse di funzioni. La tabella 144.12 descrive brevemente alcuni comandi a disposizione; in particolare, i comandi getopts e set sono ripresi anche in sezioni separate.

È bene ricordare che dal punto di vista della shell, il valore numerico zero corrisponde a Vero dal punto di vista logico, mentre qualunque valore diverso da zero corrisponde a Falso.

Tabella 144.12. Descrizione sintetica di alcuni comandi interni di una shell POSIX.

Comando Descrizione
:[argomenti]
Ciò che inizia con il simbolo : non viene eseguito. Si ottiene solo l'espansione degli argomenti e l'esecuzione della ridirezione. Il valore restituito alla fine è sempre zero.
. file_script [argomenti]
Vengono letti ed eseguiti i comandi contenuti nel file indicato. Se il nome del file non fa riferimento a un percorso, questo viene cercato all'interno dei vari percorsi elencati dalla variabile PATH (ci sono shell che cercano il file anche nella directory corrente). Se vengono forniti degli argomenti, questi diventano i parametri posizionali dello script. Il valore restituito dallo script è: quello dell'ultimo comando eseguito al suo interno; zero (Vero) se non vengono eseguiti comandi; Falso (un valore diverso da zero) se il file non è stato trovato.
alias [nome[=valore]]...
Il comando alias permette di definire un alias, oppure di leggere il contenuto di un alias particolare, o di elencare tutti gli alias esistenti.
Se viene utilizzato senza argomenti, emette attraverso lo standard output la lista degli alias nella forma nome=valore. Se viene indicato solo il nome di un alias, ne viene emesso il nome e il contenuto. Se si utilizza la sintassi completa si crea un alias nuovo.
La coppia nome=valore deve essere scritta senza lasciare spazi prima e dopo del segno di uguaglianza (=).
Il comando alias restituisce il valore Falso quando è stato indicato un alias inesistente senza valore da assegnare, negli altri casi restituisce Vero.
bg [specificazione_del_job]
Mette sullo sfondo il job indicato, come se fosse stato avviato aggiungendo il simbolo e-commerciale (&) alla fine. Se non viene specificato il job, viene messo sullo sfondo quello corrente, dal punto di vista della shell. Se l'operazione riesce, il valore restituito è zero.
break [n]
Interrompe un ciclo for, while o until. Se viene specificato il valore numerico n, l'interruzione riguarda n livelli. Il valore n deve essere maggiore o uguale a uno. Se n è maggiore dei cicli annidati in funzione, vengono semplicemente interrotti tutti. Il valore restituito è zero purché ci sia un ciclo da interrompere.
cd [directory]
Cambia la directory corrente. Se non viene specificata la destinazione, si intende la directory contenuta nella variabile HOME (che di solito corrisponde alla directory personale dell'utente). Il funzionamento di questo comando può essere alterato dal contenuto della variabile CDPATH che può indicare una serie di percorsi di ricerca per la directory su cui ci si vuole spostare. Di norma, la variabile CDPATH è opportunamente vuota, in modo da fare riferimento semplicemente alla directory corrente.
command comando [argomento...]
Esegue un «comando» con degli argomenti eventuali. Il comando che si avvia può essere solo un comando interno oppure un programma, mentre sono escluse espressamente le funzioni.
continue [n]
Riprende, a partire dall'iterazione successiva, un ciclo for, while o until. Se viene specificato il valore numerico n, il salto riguarda n livelli. Il valore n deve essere maggiore o uguale a uno. Se n è maggiore dei cicli annidati in funzione, si fa riferimento al ciclo più esterno. Il valore restituito è zero, a meno che non ci sia alcun ciclo da riprendere.
echo [-n] [argomento...]
Emette gli argomenti separati da uno spazio. Restituisce sempre il valore zero. echo riconosce alcune sequenze di escape che possono essere utili per comporre il testo da visualizzare. Queste sono elencate nella tabella 144.13.
L'opzione -n consente di impedire che alla fine del testo visualizzato sia inserito il codice di interruzione di riga finale, in modo che il testo emesso successivamente prosegua di seguito.
Si osservi che la shell Bash non riconosce le sequenze di escape se non si aggiunge espressamente l'opzione -e, oppure si abilita l'opzione xpg_echo con il comando: shopt -s xpg_echo.
eval [argomento...]
Esegue gli argomenti come parte di un comando unico. Restituisce il valore restituito dal comando rappresentato dagli argomenti. Se non vengono indicati argomenti, o se questi sono vuoti, restituisce Vero.
exec [ comando [argomenti]]
Se viene specificato un comando (precisamente deve essere un programma), questo viene eseguito rimpiazzando la shell, in modo da non generare un nuovo processo. Se sono stati indicati degli argomenti, questi vengono passati regolarmente al comando.
Il fatto di rimpiazzare la shell implica che, al termine dell'esecuzione del programma, non c'è più la shell. Se si utilizza questo comando da una finestra di terminale, questa potrebbe chiudersi semplicemente, oppure, se si tratta di una shell di login potrebbe essere riavviata la procedura di accesso.
exit [n]
Termina l'esecuzione della shell restituendo il valore n. Se viene omessa l'indicazione esplicita del valore da restituire, viene utilizzato quello dell'ultimo comando eseguito.
export nome...
Le variabili elencate vengono segnate per l'esportazione, nel senso che vengono trasferite all'ambiente dei programmi eseguiti successivamente all'interno della shell stessa.
fg [job]
Pone il job indicato in primo piano, ovvero in foreground. Se non viene specificato il job, si intende quello attuale, ovvero, l'ultimo a essere stato messo sullo sfondo (background).
getopts stringa_di_opzioni \
  \nome_di_variabile [argomenti]
Il comando interno getopts serve per facilitare la realizzazione di script in cui si devono analizzare le opzioni della riga di comando. Ogni volta che viene chiamato, getopts analizza l'argomento successivo nella riga di comando, restituendo le informazioni relative attraverso delle variabili di ambiente. Per la precisione, getopts analizza gli argomenti finali della sua stessa riga di comando (quelli che sono stati indicati nello schema sintattico come un elemento facoltativo) e in mancanza di questi utilizza il contenuto del parametro @. L'utilizzo di getopts può risultare complesso, pertanto viene descritto meglio in una sezione apposita.
hash [-r] [comando...]
Per ciascun comando indicato, viene determinato e memorizzato il percorso assoluto.
Se non viene dato alcun argomento, si ottiene l'elenco dei comandi memorizzati.
Se si usa l'opzione -r si cancellano i percorsi memorizzati.
jobs [job...]
Quello mostrato rappresenta lo schema sintattico dell'utilizzo comune di jobs, che serve a elencare i job attivi.
Se viene indicato esplicitamente un job, l'elenco risultante è ristretto alle sole informazioni su quel job.
kill [-s segnale] [pid | job]...
kill -l [numero_del_segnale]
Invia il segnale indicato al processo identificato dal numero del PID o dal job. Il segnale viene definito attraverso un nome, come per esempio KILL (per garantire la compatibilità massima conviene evitare l'uso del prefisso SIG), o un numero di segnale. Se non viene indicato il tipo di segnale da inviare, si intende TERM. Un argomento -l elenca i nomi dei segnali corrispondenti ai numeri eventualmente indicati.
typeset [nome[=valore]]
local [nome[=valore]]
Permette di dichiarare delle variabili ed eventualmente anche di attribuirgli dei valori. Se non vengono forniti nomi di variabili da creare, vengono visualizzati i nomi di quelle esistenti con i loro valori.
Il comando typeset prevede diverse opzioni per attribuire caratteristiche particolari alle variabili, ma in generale, per problemi di compatibilità, conviene usarlo senza opzioni, all'interno delle funzioni, per creare delle variabili locali. Per questa ragione, viene qui abbinato al comando local, che dovrebbe permettere di creare esclusivamente delle variabili locali all'interno delle funzioni.
pwd
Emette il percorso assoluto della directory corrente. Se viene usata l'opzione -P, i percorsi che utilizzano collegamenti simbolici vengono tradotti in percorsi reali.
Restituisce zero se non si verifica alcun errore mentre si legge il percorso della directory corrente.
read [-p prompt] variabile...
Viene letta una riga dallo standard input, assegnando la prima parola di questa riga alla prima variabile indicata come argomento, assegnando la seconda parola alla seconda variabile e così via. All'ultima variabile indicata nella riga di comando viene assegnata la parte restante della riga dello standard input che non sia stata attribuita diversamente. Per determinare la separazione in parole della riga dello standard input si utilizzano i caratteri contenuti nella variabile IFS.
L'opzione -p permette di definire un invito particolare. Questo viene visualizzato solo se l'input proviene da un terminale.
readonly [variabile...]
readonly -p
Le variabili indicate vengono marcate per la sola lettura e i valori di queste non possono essere cambiati dagli assegnamenti successivi. Se viene indicata l'opzione -p, si ottiene una lista di tutti i nomi a sola lettura.
return [n]
Termina l'esecuzione di una funzione restituendo il valore n. Se viene omessa l'indicazione di questo valore, la funzione che termina restituisce il valore restituito a sua volta dall'ultimo comando eseguito al suo interno. Se il comando return viene utilizzato al di fuori di una funzione, ma sempre all'interno di uno script, termina l'esecuzione dello script stesso.
set [{-|+}x]...
set {-|+}o [modalità]
set valore_param_1 \
  \[valore_param_2...]
set -- [valore_param_1 \
  \[valore_param_2...]]
Questo comando, se usato senza argomenti, emette l'impostazione generale della shell, nel senso che vengono visualizzate tutte le variabili di ambiente e le funzioni. Se si indicano degli argomenti si intendono alterare alcune modalità (opzioni) legate al funzionamento della shell.
Dal momento che si tratta di un comando molto complesso, il suo utilizzo viene descritto in una sezione apposita.
shift [n]
I parametri posizionali da n+1 in avanti sono spostati a partire dal primo in poi (il parametro zero non viene coinvolto). Se n è 0, nessun parametro viene cambiato. Se n non è indicato, il suo valore predefinito è uno. Il valore di n deve essere un numero non negativo minore o uguale al parametro # (cioè al numero di parametri posizionali esistenti). Se n è più grande del parametro #, i parametri posizionali non vengono modificati.
Restituisce Falso se n è più grande del parametro # o minore di zero; altrimenti restituisce Vero.
test espressione_condizionale
[ espressione_condizionale ]
Risolve (valuta) l'espressione indicata (la seconda forma utilizza semplicemente un'espressione racchiusa tra parentesi quadre). Il valore restituito può essere Vero (corrispondente a zero) o Falso (corrispondente a uno) ed è pari al risultato della valutazione dell'espressione. Le espressioni possono essere unarie o binarie. Le espressioni unarie sono usate spesso per esaminare lo stato di un file. Vi sono operatori su stringa e anche operatori di comparazione numerica. Ogni operatore e operando deve essere un argomento separato.
Se si usa la forma tra parentesi quadre, è indispensabile che queste siano spaziate dall'espressione da valutare.
Nella tabella 144.14 vengono elencate le espressioni elementari che possono essere utilizzate in questo modo.
times
Emette i tempi di utilizzo accumulati.
trap [argomento] [segnale]
Il comando espresso nell'argomento deve essere letto ed eseguito quando la shell riceve il segnale, o i segnali indicati. Se non viene fornito l'argomento, o viene indicato un trattino (-) al suo posto, tutti i segnali specificati sono riportati al loro valore originale (i valori che avevano al momento dell'ingresso nella shell). Se l'argomento fornito corrisponde a una stringa nulla, questo segnale viene ignorato dalla shell e dai comandi che questo avvia. Se il segnale è EXIT, pari a zero, il comando contenuto nell'argomento viene eseguito all'uscita della shell.
Se viene utilizzato senza argomenti, trap emette la lista di comandi associati con ciascun numero di segnale. I segnali intercettati sono riportati al loro valore originale in un processo discendente quando questo viene creato.
type nome...
Determina le caratteristiche di uno o più comandi indicati come argomento.
Restituisce Vero se uno qualsiasi degli argomenti viene trovato, Falso se non ne viene trovato alcuno.
ulimit [opzioni] [limite] 
Fornisce il controllo sulle risorse disponibili per la shell e per i processi avviati da questa, sui sistemi che permettono un tale controllo. Il valore del limite può essere un numero nell'unità specificata per la risorsa, o il valore unlimited.
Se l'indicazione dell'entità del limite viene omessa, si ottiene l'informazione del valore corrente. Quando viene specificata più di una risorsa, il nome del limite e l'unità vengono emessi prima del valore.
Il controllo pratico dei limiti impostati in questo modo dipende dal sistema operativo, che potrebbe anche ignorarne alcuni, per carenze realizzative nelle funzioni che dovrebbero attuare questi compiti.
Se il limite viene espresso, questo diventa il nuovo valore per la risorsa specificata. Se non viene indicata alcuna opzione, si assume normalmente -f. I valori, a seconda dei casi, sono espressi in multipli di 1 024 byte, o in «blocchi» da 512 byte, tranne per -t che è riferito a secondi e -n che rappresenta una quantità precisa.
Il valore restituito è zero se non vengono commessi errori.
La tabella 144.15 riepiloga le opzioni e i limiti più comuni che possono essere impostati con ulimit.
umask [modalità]
La maschera dei permessi per la creazione dei file dell'utente viene modificata in modo da farla coincidere con la modalità indicata. Generalmente può essere inserita la modalità soltanto in forma di numero ottale. Se la modalità viene omessa si ottiene il valore corrente della maschera.
unalias [-a] [nome_di_alias...]
Rimuove l'alias indicato dalla lista degli alias definiti. Se viene fornita l'opzione -a, sono rimosse tutte le definizioni di alias.
unset [-v] nome_variabile...
unset -f nome_funzione...
Vengono rimosse le variabili o le funzioni indicate. Se viene utilizzata l'opzione -f, si fa riferimento espressamente a funzioni; se si indica l'opzione -v ci si riferisce espressamente a variabili. Se non si indicano opzioni e ci può essere ambiguità tra i nomi, vengono rimosse le variabili.
wait [n]
Attende la conclusione del processo specificato e restituisce il suo valore di uscita. Il numero n può essere un PID o un job; se viene indicato un job, si attende la conclusione di tutti i processi nel condotto di quel job. Se n non viene indicato, si aspetta la conclusione di tutti i processi discendenti ancora attivi, restituendo il valore zero. Se n specifica un processo o un job che non esiste, viene restituito il valore Falso, altrimenti il valore restituito è lo stesso dell'ultimo processo o job di cui si è attesa la conclusione.

Tabella 144.13. Alcune sequenze di escape che possono essere riconosciute dal comando echo.

Codice Descrizione
\\
Inserisce la barra obliqua inversa (\).
\a
Inserisce il codice <BEL> (avvisatore acustico).
\b
Inserisce il codice <BS> (backspace).
\c
Alla fine di una stringa previene l'inserimento di una nuova riga.
\f
Inserisce il codice <FF> (formfeed).
\n
Inserisce il codice <LF> (linefeed).
\r
Inserisce il codice <CR> (carriage return).
\t
Inserisce una tabulazione normale (<HT>).
\v
Inserisce una tabulazione verticale (<VT>).
\nnn
Inserisce il carattere corrispondente al codice ottale n.

Tabella 144.14. Espressioni per il comando test.

Espressione Descrizione
-e file
Vero se il file esiste ed è di qualunque tipo.
-b file
Vero se il file esiste ed è un dispositivo a blocchi.
-c file
Vero se il file esiste ed è un dispositivo a caratteri.
-d file
Vero se il file esiste ed è una directory.
-f file
Vero se il file esiste ed è un file normale.
-h file
Vero se il file esiste ed è un collegamento simbolico.
-p file
Vero se il file esiste ed è un file FIFO (pipe con nome).
-S file
Vero se il file esiste ed è un socket (socket di dominio Unix).
-t
Vero se lo standard output è aperto su un terminale.
-g file
Vero se il file esiste ed è impostato il suo bit SGID.
-u file
Vero se il file esiste ed è impostato il suo bit SUID.
-k file
Vero se il file ha il bit Sticky attivo.
-r file
Vero se il file esiste ed è leggibile.
-w file
Vero se il file esiste ed è scrivibile.
-x file
Vero se il file esiste e dispone del permesso di esecuzione, oppure se la directory esiste e c'è il permesso di attraversamento.
-O file
Vero se il file esiste e appartiene all'UID efficace dell'utente attuale.
-G file
Vero se il file esiste e appartiene al GID efficace dell'utente attuale.
-s file
Vero se il file esiste e ha una dimensione maggiore di zero.
file1 -nt file2
Vero se il primo file ha la data di modifica più recente.
file1 -ot file2
Vero se il primo file ha la data di modifica più vecchia.
file1 -et file2
Vero se i due nomi corrispondono allo stesso inode.
stringa
Vero se la stringa è diversa dalla stringa nulla.
-z stringa
Vero se la lunghezza della stringa è zero.
-n stringa
Vero se la lunghezza della stringa è diversa da zero.
stringa1 = stringa2
Vero se le stringhe sono uguali.
stringa1 != stringa2
Vero se le stringhe sono diverse.
stringa1 < stringa2
Vero se la prima stringa è lessicograficamente precedente.
stringa1 > stringa2
Vero se la prima stringa è lessicograficamente successiva.
op1 -eq op2
Vero se gli operandi hanno valori numerici uguali.
op1 -ne op2
Vero se gli operandi hanno valori numerici differenti.
op1 -lt op2
Vero se il primo operando ha un valore numerico inferiore al secondo.
op1 -le op2
Vero se il primo operando ha un valore numerico inferiore o uguale al secondo.
op1 -gt op2
Vero se il primo operando ha un valore numerico maggiore del secondo.
op1 -ge op2
Vero se il primo operando ha un valore numerico maggiore o uguale al secondo.
! espressione
Inverte il risultato logico dell'espressione.
espressione -a espressione
Vero se entrambe le espressioni danno un risultato Vero.
espressione -o espressione
Vero se almeno un'espressione dà un risultato Vero.
(espressione)
Vero se il risultato dell'espressione è Vero.

Tabella 144.15. Opzioni per l'uso del comando ulimit.

Opzione Descrizione
-H
Viene impostato il limite fisico (hard) per la data risorsa. Un limite fisico non può essere aumentato una volta che è stato impostato. Se non viene specificata questa opzione, si intende l'opzione -S in modo predefinito.
-S
Viene impostato il limite logico (soft) per la data risorsa. Un limite logico può essere aumentato fino al valore del limite fisico. Questa opzione è predefinita se non viene specificata l'opzione -H.
-a
Sono riportati tutti i limiti correnti.
-c
La grandezza massima dei file core creati, espressa in blocchi che dovrebbero essere di 512 byte.
-d
La grandezza massima del segmento dati di un processo, in multipli di 1 024 byte.
-f
La grandezza massima dei file creati dalla shell, espressa in blocchi che dovrebbero essere di 512 byte.
-m
La grandezza massima della memoria occupata, in multipli di 1 024 byte.
-s
La grandezza massima della pila del processo (stack), in multipli di 1 024 byte.
-t
Il massimo quantitativo di tempo di CPU in secondi.
-n
Il numero massimo di descrittori di file aperti (la maggior parte dei sistemi non permette che questo valore sia impostato, consentendo solo la sua lettura).

144.4.1   Comando «getopts»

Il comando interno getopts è qualcosa di diverso dalle solite cose. Serve per facilitare la realizzazione di script in cui si devono analizzare le opzioni della riga di comando.

getopts stringa_di_opzioni nome_di_variabile [argomenti]

Ogni volta che viene chiamato, getopts analizza l'argomento successivo nella riga di comando, restituendo le informazioni relative attraverso delle variabili di ambiente. Per la precisione, getopts analizza gli argomenti finali della sua stessa riga di comando (quelli che sono stati indicati nello schema sintattico come un elemento facoltativo) e in mancanza di questi utilizza il contenuto del parametro @. Si osservi l'esempio:

getopts stringa_di_opzioni nome_di_variabile

Quanto appare sopra è esattamente uguale a:

getopts stringa_di_opzioni nome_di_variabile $@

Il comando getopts dipende in particolare dalla variabile OPTIND, che contiene l'indice di scansione di questi argomenti. Il suo valore iniziale predefinito è pari a uno, corrispondente al primo elemento, incrementato successivamente ogni volta che si utilizza getopts. Se per qualche motivo si dovesse ripetere una scansione (degli stessi, o di altri argomenti), occorrerebbe inizializzare nuovamente tale variabile al valore uno.

Per funzionare, getopts richiede due informazioni: una stringa contenente le lettere delle opzioni previste; il nome di una variabile di ambiente da creare e inizializzare di volta in volta con il nome dell'opzione individuata. Se è previsto che un'opzione di quelle da scandire sia seguita da un argomento, quell'argomento viene inserito nella variabile di ambiente OPTARG. La stringa che definisce le lettere delle opzioni è composta proprio da quelle stesse lettere, che possono essere seguite dal simbolo due punti (:) se si vuole specificare la presenza di un argomento.

Per cominciare, si osservi l'esempio seguente, in cui viene mostrato uno script elementare anche se piuttosto lungo:

#!/bin/sh
echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

echo "Indice opzioni: $OPTIND"
getopts a:b:c:defg OPZIONE -a ciao -b come -c stai -d -e -f -g -h -i
echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."

Come si può notare, getopts viene avviato sempre nello stesso modo (soprattutto con gli stessi argomenti da scandire); inoltre, subito prima viene visualizzato il contenuto della variabile OPTIND e dopo viene visualizzato il risultato della scansione. Ecco cosa si ottiene:

Indice opzioni: 1
Opzione "a" con argomento ciao.
Indice opzioni: 3
Opzione "b" con argomento come.
Indice opzioni: 5
Opzione "c" con argomento stai.
Indice opzioni: 7
Opzione "d" con argomento .
Indice opzioni: 8
Opzione "e" con argomento .
Indice opzioni: 9
Opzione "f" con argomento .
Indice opzioni: 10
Opzione "g" con argomento .
Indice opzioni: 11
./prova.sh: illegal option -- h
Opzione "?" con argomento .
Indice opzioni: 11
./prova.sh: illegal option -- i
Opzione "?" con argomento .

In pratica, sono valide solo le opzioni dalla lettera «a» alla lettera «g», inoltre le prime tre (dalla «a» alla «c») richiedono un argomento. Si può osservare che le opzioni -h e -i, che sono state aggiunte volutamente, sono in più e getopts ne ha segnalato la presenza come un errore.

Vale la pena di osservare anche l'andamento dell'indice rappresentato dalla variabile OPTIND: nel caso delle opzioni -a, -b e -c, l'incremento è di due unità perché c'è anche un argomento di queste.

Il comando getopts restituisce un valore diverso da zero (Falso) tutte le volte che si verifica un errore. In questo modo, diventa agevole il suo inserimento al posto di un'espressione condizionale, come nell'esempio seguente, in cui si fa la scansione delle opzioni fornite allo script, ovvero quelle contenute nel parametro @:

#!/bin/sh
while getopts a:b:c:defg OPZIONE
do
    echo "Opzione \"${OPZIONE}\" con argomento ${OPTARG}."
done

Al primo errore, il ciclo termina e non viene mostrato il messaggio relativo.

In condizioni normali, è più probabile che si utilizzi una struttura case per analizzare la scansione delle opzioni, come nell'esempio seguente, dove è stata aggiunta anche l'inizializzazione della variabile OPTIND a titolo precauzionale, per garantire che la scansione parta dall'inizio:

#!/bin/sh
OPTIND=1
while getopts :a:b:c:defg OPZIONE
do
    case $OPZIONE in
        a) echo "Opzione \"a\" con argomento $OPTARG."          ;;
        b) echo "Opzione \"b\" con argomento $OPTARG."          ;;
        c) echo "Opzione \"c\" con argomento $OPTARG."          ;;
        d) echo "Opzione \"d\" che non richiede argomento."     ;;
        e) echo "Opzione \"e\" che non richiede argomento."     ;;
        f) echo "Opzione \"f\" che non richiede argomento."     ;;
        g) echo "Opzione \"g\" che non richiede argomento."     ;;
        *) echo "È stata indicata un'opzione non valida."       ;;
    esac
done

Questo esempio è diverso da quelli precedenti, soprattutto per la stringa di definizione delle opzioni da scandire: questa stringa inizia con il simbolo due punti (:). In questo modo, si vuole evitare che getopt restituisca Falso quando si verifica un errore negli argomenti.

Il comando getopts utilizza anche un'altra variabile di ambiente: OPTERR. Questa variabile contiene normalmente il valore uno; se le viene assegnato zero, si inibiscono tutte le segnalazioni di errore.

144.4.2   Comando «set»

Il comando set, se usato senza argomenti, emette l'impostazione generale della shell, nel senso che vengono visualizzate tutte le variabili di ambiente e le funzioni. Se si indicano degli argomenti si intendono alterare alcune modalità (opzioni) legate al funzionamento della shell.

set [{-|+}x]...
set {-|+}o [modalità]
set valore_param_1 [valore_param_2 ... [valore_param_n]]
set -- [valore_parametro_1 [valore_parametro_2...]]

Quasi tutte le modalità in questione sono rappresentate da una lettera alfabetica, con un qualche significato mnemonico. L'attivazione di queste modalità può essere verificata osservando il contenuto del parametro $-:

echo $-[Invio]

Si potrebbe ottenere una stringa come quella seguente:

imH

Le lettere che si vedono («i», «m» e «H») rappresentano ognuna l'attivazione di una modalità particolare, dove però set può intervenire solo su alcune di queste. Gli argomenti normali del comando set sono le lettere delle modalità che si vogliono attivare o disattivare: se le lettere sono precedute dal segno - si specifica l'attivazione di queste, mentre se sono precedute dal segno + si specifica la loro disattivazione.

Il comando set può essere usato per modificare le modalità di funzionamento anche attraverso l'opzione -o, oppure +o, che deve essere seguita da una parola chiave che rappresenta la modalità stessa. I segni - e + rappresentano ancora l'attivazione o la disattivazione della modalità corrispondente. Le modalità a cui si accede attraverso l'opzione -o (o +o) non sono esattamente le stesse che si possono controllare altrimenti.

Il comando set può servire anche per modificare il contenuto dei parametri posizionali. Per questo, se ci sono degli argomenti che seguono la definizione dell'ultima modalità, vengono interpretati come i valori da assegnare ordinatamente a questi parametri. In particolare, se si utilizza la forma set --, si interviene su tutti i parametri: se non si indicano argomenti, si eliminano tutti i parametri; se ci sono altri argomenti, questi diventano ordinatamente i nuovi parametri, mentre tutti quelli precedenti vengono eliminati.

Se viene utilizzato il comando set -o, si ottiene l'elenco delle impostazioni attuali.

Il comando set restituisce Vero se non viene incontrata un'opzione errata.

Segue la descrizione di alcune modalità, che potrebbero essere riconosciute dalla maggior parte delle shell POSIX.

Modalità Descrizione
{-|+}a
{-|+}o allexport
Le variabili che vengono modificate o create, sono marcate automaticamente per l'esportazione verso l'ambiente per i comandi avviati dalla shell.
{-|+}b
{-|+}o notify
Fa in modo che venga riportato immediatamente lo stato di un job sullo sfondo che termina. Altrimenti, questa informazione viene emessa subito prima dell'invito primario successivo.
{-|+}e
{-|+}o errexit
Termina immediatamente se un comando qualunque conclude la sua esecuzione restituendo uno stato diverso da zero. La shell non esce se il comando che fallisce è parte di un ciclo until o while, di un'istruzione if, di una lista && o ||, o se il valore restituito dal comando è stato invertito per mezzo di !.
{-|+}f
{-|+}o noglob
Disabilita l'espansione di percorso (quello che riguarda i caratteri jolly nei nomi di file e directory).
{-|+}m
{-|+}o monitor
Abilita il controllo dei job. Questa modalità è attiva in modo predefinito per le shell interattive.
{-|+}n
{-|+}o noexec
Legge i comandi, ma non li esegue. Ciò può essere usato per controllare gli errori di sintassi di uno script di shell. Questo valore viene ignorato dalle shell interattive.
{-|+}u
{-|+}o nounset
Fa in modo che venga considerato un errore l'utilizzo di variabili non impostate (predisposte) quando si effettua l'espansione di una variabile (o di un parametro). In tal caso, quindi, la shell emette un messaggio di errore e, se il funzionamento non è interattivo, termina restituendo un valore diverso da zero.
{-|+}v
{-|+}o verbose
Emette le righe inserite nella shell appena queste vengono lette.
{-|+}x
{-|+}o xtrace
Nel momento in cui si eseguono dei comandi, viene emesso il comando stesso attraverso lo standard output preceduto da quanto contenuto nella variabile PS4.
{-|+}C
{-|+}o noclobber
Disabilita la sovrascrittura dei file preesistenti a seguito di una ridirezione dell'output attraverso l'uso degli operatori >, >& e <>. Questa impostazione può essere scavalcata (in modo da riscrivere i file) utilizzando l'operatore di ridirezione >| al posto di >.
In generale sarebbe meglio evitare di intervenire in questo modo, dal momento che ciò non è conforme allo standard di utilizzo normale.

L'esempio seguente mostra come modificare il gruppo dei parametri posizionali:

set -- ciao come stai?[Invio]

echo $1[Invio]

ciao

echo $2[Invio]

come

echo $3[Invio]

stai?

Appunti di informatica libera 2008 --- Copyright © 2000-2008 Daniele Giacomini -- <appunti2 (ad) gmail·com>


Dovrebbe essere possibile fare riferimento a questa pagina anche con il nome shell_posix_programmazione.htm

[successivo] [precedente] [inizio] [fine] [indice generale] [indice ridotto] [indice analitico] [home]

Valid ISO-HTML!

CSS validator!

Gjlg Metamotore e Web Directory