Guida Bash Scripting

Vorrei replicare una delle migliori guide per programmare in Bash Scripting ...

 


ONDAQUADRA ~ LiNUX                                      #07 - 01/08/2002
SHELL SCRiPTiNG: BASH [Domine] 0x12/0x19

Shell scripting: Bash - 27/08/2001 - by Domine

Mail: Questo indirizzo email è protetto dagli spambots. È necessario abilitare JavaScript per vederlo. WWW: http://www.autistici.org/domine/index.php IRC: Domine @ IRCNet, AzzurraNet

Perchè scripting in Bash? Semplicemente, può sempre tornare utile nella gestione dei sistemi Unix (ad esempio, per la manutenzione tramite crond e soci :-). Ovviamente non parlerò di tutti i cazzi come i settaggi delle impostazioni di Bash ecc.. bensì di ciò che sarà più utile per la stesura di script utili.

ToC:

  1. INTRO
  2. VARIABILI E PARAMETRI
  3. QUOTING
  4. LISTE DI COMANDI
  5. STRUTTURE CONDIZIONALI E CICLI
  6. ESPRESSIONI CONDIZIONALI
  7. FUNZIONI
  8. ARRAY
  9. ESPANSIONE
  10. COMANDI INTERNI (BUILTINS)
  11. REDIREZIONI

INTRO

Innanzitutto, ogni script è aperto dalla stringa

#!/bin/bash

in cui si indica di avviare la shell come interprete. I comandi all'interno del file verranno eseguiti sequenzialmente, come se noi stessi dal normale prompt li eseguissimo uno alla volta. Valgono quindi tutti quei comandi che avete sempre usato per gestire il vostro sistema (copia, cancella ecc ecc) oltre ad una serie di comandi che la shell fornisce autonomamente.

VARIABILI E PARAMETRI

In Bash la dichiarazione delle variabili avviene tramite

nome_della_variabile="valore"

Non è necessario dichiarare il tipo di valore, poichè la shell stessa provvederà a comportarsi a seconda del tipo di variabile. Nel caso si faccia riferimento ad una variabile non dichiarata oppure a una variabile vuota, questa sarà automaticamente riempita con una stringa vuota. Ogni volta che si vorrà fare riferimento a una variabile, basterà anteporre al suo nome il simbolo $

prova="blahblah"        # Il cancelletto crea una riga di commento     
echo $prova # Echo mostra sullo schermo "blahblah"

In questo casò, la shell sostituisce a $prova un'altra stringa tramite il processo detto "espansione", cosa che accade ogni volta che con una qualsiasi dicitura si fa riferimento a una o più parole

ls -l

L'asterisco in questo caso fa riferimento a tutte le directory e ai file non nascosti nella dir corrente. (vedi ESPANSIONE)

Sia le variabili sia i parametri sono case sensitive.

Per parametri si intendono delle variabili che hanno un valore particolare nell'ambito della shell, e si distinguono in:

  • PARAMETRI POSIZIONALI

Ossia gli argomenti passati allo script. Con $0 si indica il nome dello script, mentre con $1, $2, $3 si indicano rispettivamente il primo, il secondo e il terzo argomento della riga di comando, e così via. Quando un parametro posizionale composto da 2 o più cifre deve essere espanso, deve essere contenuto fra parentesi graffe (es. ${13} ).

  • PARAMETRI SPECIALI

Si tratta di variabili a cui si può far solo riferimento, e non vi si può assegnare alcun valore. Esse sono:

  • Espande all'insieme di tutti i parametri posizionali, uniti tra di loro in un unica stringa. Essi sono separati dal primo carattere della variabile speciale IFS (ossia uno spazio).
@       Espande all'insieme di tutti i parametri posizionali. Se       
però $@ è racchiusa tra apici doppi ("), essa si riferirà
non ad un unica stringa come il parametro precedente, bensì
a più parole. "@$" sarà quindi equivalente a "$1" "$2"
ecc... (utile magari per un ciclo condizionale, quindi).

# E' equivalente al numero dei parametri posizionali

? E' uguale allo stato restituito dall'ultima pipeline in
foreground
(es. se l'ultimo comando sarà stato eseguito con successo
restituirà 0, ossia VERO in un contesto booleano.)

- Restituisce i valori (flags) attivate dal comando SET

$ Restituisce il PID della shell

! E' uguale al PID dell'ultimo comando eseguito in background

0 Contiene il nome dello script in esecuzione.

Contiene l'ultimo argomento del precedente comando.
  • VARIABILI DELLA SHELL
PPID            Il PID del processo padre della shell                  
PWD La dir corrente
OLDPWD La dir precedente
UID L'UID dell'utente all'avvio della shell
EUID L'UID effettivo dell'utente all'avvio di BASH
BASH Il percorso della shell
BASHVERSINFO La versione di BASH
RANDOM Un numero intero tra 0 e 32767
SECONDS Num di secondi dall'apertura della shell
LINENO Il numero di linea in uno script o funzione
PIPESTATUS Lo stato dell'ultima pipeline
IFS Variabile usata nella suddivisione in parole
dopo una espansione (equivalente a
<spazio><tab><newline>)
PATH I percorsi in cui la shell cerca i binari dei vari
comandi
HOME La directory dell'utente
MAILPATH La directory della posta elettronica
IGNOREEOF Il numero di EOF consecutivi che fanno terminare Bash

Queste variabili ed altre ancora sull'escusivo canale MAN Educational Channel (ah, è free? Buono! man bash :-] )

QUOTING

Il quoting è il metodo utilizzato per togliere ad un determinato carattere il significato speciale che esso ha per la shell. Ad esempio metacaratteri quali

| || & && ; ;; ( ) < > <newline>

devono essere protetti per non creare equivoci. I meccanismi di quoting sono 3: escaping, apici singoli e apici doppi.

L'escaping avviene facendo precedere il carattere da uno . Nel caso questo si trovi alla fine della linea, esso annullerà il ritorno a capo, permettendo di scrivere il comando su più righe.

Es. mkdir $prova       # Crea la directory "$prova". Ogni volta che    
# vorrò riferirmi ad essa, dovrò usare lo

echo "Questa è una riga e questa ne è un'altra"

Stamperà "Questa è una riga e questa ne è un'altra". Lo mi ha permesso di distribuire il comando su 2 righe.

Utilizzando gli apici singoli ('), tutto ciò fra essi compresi mantiene il proprio significato letterale (non viene quindi "interpolato"). Altri apici singoli non possono essere annidati, neanche se preceduti dallo

Es. echo 'Come vedi da $0, questa stringa non è stata modificata'

Utilizzando gli apici doppi ("), tutto rimane inalterato fuorchè i simboli $ e ` (apice inverso), che conservano le loro caratteristiche. Anche lo , se precede $, ` oppure " riacquista il suo significato di escaper.

Es. echo "La variabile "$HOME" contiene $HOME"

# stampa: La variabile "$HOME" contiene /home/domine

LISTE DI COMANDI

Ogni comando, sia che si tratti di un programma esterno, o di una funzione o ancora di un comando interno alla shell, esegue una serie di operazioni, dopo di che restituisce un valore numerico. Nel caso in cui ci si riferisca ad un contesto booleano (vero/falso), lo zero equivarrà a vero, mentre qualunque altro valore numerico a falso. Il numero restituito da un comando è detto "stato di uscita" e, nel caso ad esempio di una funzione o di un ciclo, è determinato dall'ultima istruzione eseguita.

E' possibile utilizzare più comandi insieme tramite la stessa riga, utilizzando degli operatori condizionali che verificheranno il valore di uscita dell'istruzione che li precede. Ad esempio

make mrproper ; make xconfig ; make dep

ogni comando attende l'esecuzione del precedente per essere eseguito. Oppure la classica pipeline che passa il proprio outpu al comando successivo

cat /etc/passwd | less

Si possono utilizzare && oppure || che equivalgono a AND ed OR; il primo attende un valore di uscita positivo (vero), l'altro il contrario (falso). E' possibile annidare gruppi di comandi con le () o le {}.

(rmdir tmp || rm -rf tmp) && echo "Directory rimossa"

(le parentesi tonde possono anche modificare la priorità delle operazioni)

{

  mkdir tmp             # Le parentesi graffe permettono               
cp ~/ tmp # di disporre comandi su più linee
cd tmp

}

STRUTTURE CONDIZIONALI E CICLI

E' possibile utilizzare le strutture di controllo classiche dei linguaggi di programmazione:

  • FOR

for VAR [ in PAROLA ] do comando_1 comando_2 ... comando_n done

Non è necessario separare le istruzioni con un ; in quanto è sufficiente il ritorno a capo. Nel caso di questo ciclo, gli elementi indicati dalla PAROLA che segue "in" (se "in" viene omesso la shell utilizza i parametri posizionali) vengono posti uno per volta uguali a VAR, e per ognuno di essi verrà eseguito la serie di comandi indicata. Esempio:

for VAR # qui è come se sottintendesse "in $@" do echo $VAR done

Questa struttura elenca tutti gli argomenti passati allo script.

LISTA=$`ls ~` for i in $LISTA

do                      # ++n aggiunge 1 alla variabile n prima        
echo "$((++n)) $i" # che l'istruzione sia eseguita (poichè non
done # dichiarata, n è uguale a 0)

Genera una lista numerata degli elementi nella dir HOME.

E' anche possibile utilizzare il costrutto classico

for (( inizializzazione ; condizione ; incremento )) do ... serie di comandi ... done

Le tre espressioni all'interno delle (()) vengono verificate per ogni serie di comandi eseguita. Finchè la "condizione" non equivale a zero, for esegue "l'incremento" e la lista di comandi dopo il "do".

for (( i=0 ; i-11 ; i++ )) do echo $i # Chissà che compirà mai? :-) done

E' possibile interrompere un ciclo con una istruzione BREAK o RETURN (seguita da un numero).

  • SELECT

select VAR [ in LISTA_VALORI ] do comando_1 comando_ecc_ecc done

Con select è possibile mostrare sullo schermo una lista di opzioni e un prompt pronto a raccogliere la scelta dell'utente. Ancora una volta, un "in" omesso equivale a $@.

La stringa inserita viene copiata nella variabile $REPLY, mentre il valore ad essa associata viene assegnato a VAR, dopodichè vengono eseguite le istruzioni elencate e si ritorna all'inizio del ciclo (finchè l'utente non preme control+c o control+d, oppure finchè un'istruzione BREAK o RETURN viene eseguita).

select i in $@ # Verrà creata una lista con gli argomenti passati do echo "$REPLY è uguale a $i!" done

  • CASE

case parola in [ [(] pattern [ | pattern ] ... ) comandi ;; ] esac

Case permette l'esecuzione di determinati comandi a seconda del valore di una determinata variabile (dove c'è "parola"). La shell confronta una ad una le possibilità, e appena trova un riscontro (pattern) con le possibilità nello script esegue dei comandi, interrompendo la ricerca di altri riscontri.

case $1 in a | b | c | abc) echo "ABC";;

d)                echo "D";;                                           
e | f | ef) echo "EF";;
) echo "ma ch'rrè?";;

esac

Con il simbolo | si possono indicare possibilità diverse per un'unica opzione. In questo caso se il primo argomento passato allo script contiene a,b,c o abc stamperà ABC, altrimenti confronterà l'argomento con il pattern successivo e così via. Nel caso nessuno dei pattern contenga $1, viene attivato un pattern predefinito ( combacia con qualunque stringa). Nel caso non avvengano riscontri, la funzione restituisce 0.

  • IF

if espressione then comandi [ elif espressione; then comandi; ] ... [ else comandi; ] fi

If permette di eseguire dei comandi a seconda che una determinata condizione sia verificata o meno. Se i comandi dopo if restituiscono vero, allora vengono eseguiti i comandi seguenti then. Altrimenti, viene eseguito elif che verificherà altre condizioni e, come if, se le riscontra esegue i comandi dopo then, altrimenti passerà ad un altro, eventuale, elif. Infine, se nessuna delle condizioni è vera, esegue i comandi dopo else. Se nessuna condizione restituisce vero if restituirà 0.

if [ $UID > 0 ] # le [] sono abbreviazione del comando TEST then echo "Non hai i privilegi di root! :-P" else echo "Hai i privilegi di root! :-)" fi

Per il confronto valgono gli operatori aritmetici e logici come <,>,==,! (negazione logica, inverte il significato dell'espressione),&&,|| e così via.

  • WHILE e UNTIL

while espressione; do comandi; done until espressione; do comandi; done

While esegue una serie di comandi finchè l'espressione indicata all'inizio restituisce vero; per until vale altrettanto, finchè l'espressione restituisce falso.

x=0; while [ $x -lt 10 ] # $x > 10 (Vedi espressioni condizionali) do echo $((x++)) # Equivale a: echo $x ; $((x=x+1)) done

ESPRESSIONI CONDIZIONALI

I seguenti operatori unari e binari sono utilizzati dalla funzione test (e dalla sua versione abbreviata []) per verificare gli attributi dei file e per confrontare stringhe ed espressioni numeriche.

-a file         Vero se file esiste.                                   
-b file Vero se file esiste ed è un dispositivo a blocchi.
-c file Vero se file esiste ed è un dispositivo a caratteri.
-d file Vero se file esiste ed è una directory
-e file Vero se file esiste.
-f file Vero se file esiste ed è un file regolare.
-g file Vero se file esiste ed il bit SGID è attivo.
-h file Vero se file esiste ed è un link simbolico.
-k file Vero se file esiste è il suo bit "sticky" è attivo
-p file Vero se file esiste ed è una pipe con nome (FIFO).
-r file Vero se file esiste ed è leggibile.
-s file Vero se file esiste ed ha dimensioni maggiori di
zero.
-t fd Vero se /dev/stdout (standard output) è indirizzato
al terminale
-u file Vero se file esiste ed il bit SUID è attivo.
-w file Vero se file esiste ed ha i permessi per la
scrittura.
-x file Vero se file esiste ed è eseguibile.
-O file Vero se file esiste ed appartiene all'user id
effettivo dell'utente
-G file Vero se file esiste ed appartiene al group id
effettivo dell'utente
-L file Vero se file esiste ed è un link simbolico.
-S file Vero se file esiste ed è un socket.
-N file Vero se file esiste ed è stato modificato
dall'ultima lettura

file1 -nt file2 Vero se file1 è più recente del file2.
file1 -ot file2 Vero se file1 è più vecchio del file2.
file1 -ef file2 Vero se file1 e file2 hanno lo stesso inode
e device.
-o optname Vero se l'opzione di shell optname è attiva
(vedi SET)
-z stringa Vero se la lunghezza della stringa è zero.
-n stringa Vero se la lunghezza della stringa non è
zero.
stringa Vedi caso precedente
stringa1 == stringa2 Vero se le stringhe sono uguali (può essere
usato anche = )
stringa1 != string2 Vero se le stringhe non sono uguali.
stringa1 < stringa2 Vero se stringa1 viene lessicographicamente
prima di stringa2
stringa1 > stringa2 Vero se stringa1 viene lessicographicamente
dopo di stringa2
  • OPERATORI BINARI ARITMETICI

Arg1 e arg2 possono essere interi positivi o negativi.

arg1 -eq arg2 Vero se arg1 è uguale ad arg2. arg1 -ne arg2 Vero se arg1 non è uguale ad arg2. arg1 -lt arg2 Vero se arg1 minore di arg2. arg1 -le arg2 Vero se arg1 minore o uguale ad arg2. arg1 -gt arg2 Vero se arg1 maggiore di arg2. arg1 -ge arg2 Vero se arg1 maggiore o uguale ad arg2.

FUNZIONI

Definendo delle funzioni è possibile richiamare un gruppo di istruzioni come se si facesse riferimento a un normale comando della shell. La sintessi è

[ function ] nome () { comandi; }

Quando viene eseguita una funzione, i parametri posizionali dello script vengono momentaneamente sostituiti con gli argomenti passati alla funzione ($0 continua però a riferirsi al nome dello script). Al termine della funzione le variabili vengono ripristinate. Si possono inoltre definire delle variabili interne alla funzione con il comando local seguito dalla normale dicitura per la dichiarazione delle variabili. Le funzioni (così come le variabili) possono essere messe a disposizione di altri script della shell col comando export. Coi comandi BREAK e RETURN si interrompe l'esecuzione della funzione.

function stampa() { echo "Tieccati il valore $1" # questa funzione stampa $1 ma si

                             # tratta del "prova" passatogli           
return 0 # questo è superfluo poichè echo restituirà 0 se
# riuscirà a stampare
}
echo $1 # se lanceremo lo script senza argomenti non stampa
# nulla

if stampa prova # la funzione, come qualsiasi altra, restituisce un

# valore da testare then echo "stampa riuscita" # poichè stampa ritorna zero, l'if esegue

# questo echo else echo "boh? :-P" fi

ARRAY

Bash fornisce la possibilità di usare array mono-dimensionali. Come voi ben sapete (!) l'array è una variabile contenente più valori ordinati numericamente (gli indici delle variabili non potranno quindi essere composti da lettere). Per creare un array basta assegnare un valore a uno qualsiasi dei suoi indici, oppure usare il comando declare.

arrei[0]="Sono l'elemento numero uno! ;-)"

Gli indici degli array cominciano dallo zero. Si possono anche aggiungere più elementi contemporaneamente a un array

arrei=(valore_1 valore_2 ... valore_n)

ogni valore deve essere specificato con la sintassi

[indice]=valore

altrimenti, se "[indice]=" viene omesso, la shell assegnerà il primo indice libero al valore.

Per richiamare un valore di un array, si utilizza la forma

${nome[indice]}         # Le {} sono necessarie per evitare            
# confusioni :-P

Per indicare tutti gli elementi di un array:

${nome[*]} # oppure ${nome[@]}

Come per i parametri posizionali, se ${nome[indice]} è circondato da apici doppi, l' restituirà un'unica parola con tutti gli elementi dell'array, separati da uno spazio, mentre la @ restituirà una parola per ogni elemento.

Con

${#nome[]} # anche qui è l'equivalente di ${nome[@]}

ottengo il numero di elementi dell'array. Nel caso faccia riferimento al solo nome dell'array senza specificare l'indice (come se fosse una normale variabile), la shell sottintenderà l'indice 0.

echo $arrei # stampa: Sono l'elemento numero uno! ;-)

Per eliminare un elemento dell'array, oppure l'intero array, si utilizza il comando UNSET. Per comandi come declare, local, e readonly è possibile utilizzare un'opzione -a per specificare che si sta utilizzando un array.

ESPANSIONE

Come sopra detto, è possibile utilizzare notazioni "contratte" per riferirsi a più parole. I tipi di sostituzione, nell'ordine, sono i seguenti:

  • PARENTESI GRAFFE

E' possibile, con la sintassi

prefisso{parola_1,parola_2,parola_n}suffisso

Specificare dei persorsi alternativi. Ad esempio con

/usr/local/src/bash/{old,new,dist}/

ci si può riferire a tutti i files contenuti nelle dir

/usr/local/src/bash/old /usr/local/src/bash/new /usr/local/src/bash/dist

Si può anche nidificare più parentesi graffe. Nel caso invece ci si voglia riferire ad esse per il loro significato letterale, vanno protette con il carattere "" (vedere QUOTING). Stessa cosa vale per la virgola, ora usata come separatore.

  • TILDE

Se in una stringa è presente una tilde non quotata (~ non preceduta da ), allora essa sarà considerata equivalente a $HOME; se sono presenti degli / dopo la tilde, la shell allora cercherà un percorso all'interno della dir dell'utente (~/tmp == /home/domine/tmp), altrimenti tutto ciò che seguirà la tilde sarà considerato come uno user name (quindi ~root sarà uguale a /root, home di quell'utente). Esistono inoltre le variabili ~+ e ~- equivalenti a $PWD e $OLDPWD.

  • PARAMETRI E VARIABILI

L'espansione dei parametri e delle variabili viene introdotta dal carattere $, seguito dal nome della variabile; le parentesi graffe, opzionali, servono quando non vogliamo che del testo sia confuso col nome della variabile; sono invece obbligatorie nel caso di parametri posizionali a più cifre.

Data la variabile

testo="ba"

se volessi aggiungere a quella variabile le lettere "sh" in modo da formare un'altra parola, dovrei usare la sintassi

echo ${testo}sh

poichè se avessi indicato $testosh la shell avrebbe cercato invece un'altra variabile, inesistente.

Nel caso il nome della variabile sia preceduto da un !, la shell intenderà che il valore in essa contenuto sarà uguale al nome di un'altra variabile, che sarà a sua volta espansa nel valore che contiene (espansione indiretta). Esempio:

UNO="DUE" DUE="TRE" echo ${!UNO} # stamperà TRE

I costrutti che ora seguiranno verificano la presenza della variabile VAR e, se vuota o non dichiarata, eseguiranno diverse operazioni:

${VAR:-parola} Definisce una parola predefinita nel caso VAR non

esista

Es. echo ${VAR:-blabla} # Stampa "blabla"

${VAR:=parola} Uguale al precedente, ma inoltre assegna un valore

a VAR

Es. echo ${VAR:-blabla}; echo $VAR # nel caso del secondo echo VAR

# ha un valore

${VAR:?parola} Definisce il messaggio dello standard error

Es. echo ${VAR:?Variabile non definita}

# bash: VAR: Variabile non definita

${VAR:+parola} Cambia il valore della variabile nel caso questa NON

sia vuota

Es. echo ${VAR:+parola} # Stamperà "". Se VAR avesse un valore,

# stamperebbe"parola"

${VAR:offset:length} Stampa numero length caratteri a partire dal

                     carattere numero offset (length dev'essere        
maggiore di 0, se è omesso verrà stampata la
variabile da offset fino alla fine).

Es. PROVA="Vercingitorige"; echo ${PROVA:8:4} # Stampa "tori"

${!prefisso} Espande al nome delle variabili che cominciano per

prefisso.

${#VAR}         Restituisce il numero di caratteri in una variabile    
(oppure il numero di parametri posizionali, nel caso
di * e @).
  • COMANDI

E' possibile interagire con i risultati di un qualsiasi comando con la sintassi

$(comando)

oppure

$`comando` # !! Attento !! Apici INVERSI (` == Alt Gr + ')

Es. FILES=$(ls -l ) # Assegna a FILES i file contenuti nella dir

# corrente

     cp $(find ~ -name ".txt") ~/txt     # Copia tutti i file txt     
# in una dir

I comandi possono essere annidati (nel caso degli apici, vanno protetti con )

  • ARITMETICA

Con la sintassi

$((espressione))

la shell sostituirà ad una espressione il suo risultato.

Es. NUM=3 ; echo "$(((2+2)*$NUM))" # Stamperà 12

Anche le espressioni possono essere annidate. Per quanto riguarda gli operatori, valgono tutti quelli degli altri linguaggi di programmazione (li avete anche studiati alle elementari... +, -, , / !!!)

  • SUDDIVISIONE DELLE PAROLE

La shell cerca innanzitutto di suddividere in parole ciò che è contenuto in apici doppi (")

Es. echo "b" # Stampa tutti i file che cominciano per "b"

Le parole vengono suddivise tra loro dal primo carattere della variabile IFS (lo spazio). Nel caso seguente

PROVA="b" ; echo "$PROVA"

verrà stampato però il contenuto letterale di $PROVA ("b").

  • PERCORSO (PATHNAME)

Alla presenza dei metacaratteri *,?,[] la shell sostituisce un elenco ordinato alfabeticamente dei riscontri verificati (vedi ls *)

  • Vale per qualsiasi stringa, compresa quella vuota ? Vale per qualunque carattere singolo [abcn] Vale per i caratteri all'interno delle parentesi

    (soltanto a,b,c ed n quindi) [a-z] Vale per l'intervallo di caratteri compreso fra quelli

    specificati (quindi le lettere dalla a alla z)

Utilizzando il punto esclamativo subito dopo la [, si inverte il significato del contenuto delle parentesi. Nel caso si voglia comprendere negli intervalli il - e le parentesi [ ], questi simboli vanno specificati all'inizio o alla fine del gruppo di caratteri.

COMANDI INTERNI (BUILTINS)

Ecco una lista dei principali builtin, comandi appartenenti alla shell e non a binari esterni. (per saperne di più: rtfm! :-P)

  • . (SOURCE)

. file [argomenti] source file [argomenti]

Esegue i comandi contenuti all'interno di FILE. Se non viene specificato il percorso (assenza di /), la shell cerca il file all'interno delle dir indicate in $PATH. Gli argomenti passati tramite source diventano i parametri posizionali del file eseguito. Restituisce lo stato dell'ultimo comando eseguito all'interno del file, oppure falso se il file non esiste.

  • ALIAS

alias [-p] [nome[=valore] ...]

Permette di definire delle scorciatoie per richiamare comandi più lunghi. Il solo "alias" oppure "alias -p" stampano sullo schermo la lista degli alias definiti.

alias ls='ls -al' # un classico :-)

  • BG

bg [nome_del_job]

Esegue un comando in background (ossia la shell non attende il termine della sua esecuzione ma mostra ancora il prompt mentre il comando esegue delle operazioni). L'equivalente della sintassi nome_comando& . Se il job non è specificato, viene messo in background il processo attuale.

  • BREAK

break [n]

Esce da un loop for, while, until, o select. Si può specificare il numero di livelli da interrompere con la variabile n (nel caso di cicli annidati). La variabile n deve essere maggiore o uguale a 1. Restituisce 0 a meno che non c'è un ciclo da interrompere.

  • BUILTIN

builtin shell-builtin [argomenti]

Esegue il builtin specificato, passandogli degli eventuali argomenti. Restituisce il valore del builtin. E' utile quando si dà ad una funzione un nome appartenente ad un comando interno, e si vuole utilizzare comunque quel comando.

  • CD

cd [-LP] [dir]

C'è bisogno che ve lo spiego? :-) Cmq le eventuali opzioni P e L forzano il comando a seguire la struttura fisica della directory e non link simbolici, e viceversa. Il valore predefinito di DIR è $HOME, mentre "cd -" carica la dir $OLDPWD .

  • COMMAND

command [-pVv] comando [argomenti]

Esegue il comando con gli argomenti specificati; il comando deve essere interno alla shell o presente in un dei percorsi di $PATH, quindi evita che vengano eseguite funzioni dichiarate dallo script. L'opzione -p fa sì che venga utilizzata una serie di percorsi di ricerca predefiniti al posto di $PATH in modo da garantire il riscontro di tutte le utilities standard. Le opzioni -V e -v producono delle informazioni inerenti il comando usato. Se una di queste due opzioni è specificata, nel caso il pogramma sia stato trovato command restituirà 0, altrimenti 1. Se non sono state specificate, nel caso il programma non sia stato trovato, restituisce 127, altrimenti il valore dell'esecuzione del comando.

  • CONTINUE

continue [n]

Riprende un ciclo interrotto di tipo for, while, until, o select dall'ultima iterazione eseguita. Tramite n (n>=1), si può ordinare di riprendere il ciclo dall'n-esima iterazione. Nel caso n sia superiore al numero di cicli previsto, continue riprenderà dall'ultimo.

  • DECLARE

declare [-afFirx] [-p] [nome[=valore]] typeset [-afFirx] [-p] [nome[=valore]]

Declare è usato per dichiare variabili e assegnargli valori o attributi. Il solo "declare", o "declare -p" mostrano le variabili attive. L'opzione "-F" mostra sullo schermo soltanto i nomi e gli attributi delle funzioni definite, mentre "-f" mostra per intero queste funzioni. Infine:

-a      Specifica che si tratta di un array                            
-i La variabile è trattata come un numero intero per cui,
quando la variabile viene assegnata, viene valutata
aritmeticamente.
-r Rende una variabile soltanto leggibile, quindi non
modificabile nè cancellabile.
-x Rende la variabile valida anche per gli altri script
(vedi EXPORT)

Sostituendo con un "+" il "-", l'opzione viene disattivata (es. +r rende modificabile una variabile) (PS: +a non può distruggere un array). Se utilizzato all'interno di una funzione, declare svolge lo stesso ruolo di local.

  • ECHO

echo [-neE] [argomenti]

Stampa gli argomenti, separati da spazi e seguiti da una newline. Restituisce sempre 0. Se "-n" è specificato, la newline finale non viene stampata. Se "-e" viene specificata, vengono abilitati i caratteri di escape sottostanti, mentre "-E" la disabilita, anche nei sistemi in cui è abilitata di default.

a     avviso acustico (bell)                                           
b backspace
c impedisce l'inserimento dinewline a fine stringa
e un carattere di escape
f form feed
n nuova linea (newline)
r ritorno a capo (carriage return)
t tabulazione orizzontale
v tabulazione verticale
\ barra obliqua (backslash)
nnn il carattere il cui codice ASCII è il valore ottale di n
(ripetuto 3 volte)
xnnn il carattere il cui codice ASCII è il valore esadecimale di n
(ripetuto 3 volte)
  • ENABLE

enable [-adnps] [-f file] [nome ...]

Abilita o disabilita le shell-builtins. Permette ad un programma avente lo stesso nome di una builtin di essere eseguito senza doverne specificare l'intero percorso. Se "-n" viene specificato, il comando NOME viene disabilitato, altrimenti viene abilitato. Per mostrare le builtin attive si usa "enable" o "enable -p", per quelle disattive "enable -n", per entrambe "enable -a". Con "-f" viene caricato come builtin un eseguibile specificato dal percorso FILE; "-d" invece rimuove una builtin dichiarata con "-f".

  • EVAL

eval [argomenti]

Gli argomenti indicati vengono concatenati ed eseguiti come un comando unico. Eval restituirà il valore di ritorno di quel comando.

  • EXEC

exec [-l] [-a nome] [comando [argomenti]]

Il comando specificato (con relativi argomenti) viene eseguito e la shell terminata, impedendo il formarsi di nuovi processi. Se viene usato "-l", un trattino viene aggiunto all'argomento numero 0; con "-a", la shell passa NOME come argomento numero zero al programma.

  • EXIT

exit [n]

Termina il processo della shell restituendo n.

  • EXPORT

export [-fn] [nome[=parola]] ... export -p

Le variabili, gli array o le funzioni (con "-f") specificate vengono rese disponibili per l' ambiente di shell dopo il termine dello script. L'opzione "-n" fa sì che le variabili specificate non possano essere esportate. Se non vengono specificate opzioni oppure se viene utilizzata "-p", viene stampato ciò che è stato esportato.

  • FG

fg [nome_del_job]

Pone il job specificato (o l'ultimo processo in background, se non viene specificato) in foreground.

  • GETOPTS

getopts stringa_opzioni nome_variabile [argomenti]

Avete presente quegli eseguibili che richiedono degli argomenti per funzionare ? Per dare all'utente la possibilità di indicare allo script dei dati in stile POSIX, getopts viene usato per il parsing dei parametri posizionali. Dato ad esempio il comando

$ ./nomescript.sh -h localhost -t 10

sappiamo che la stringa "-h" verrà contenuta in $1, "localhost" in $2 e così via... l'utilizzo di questi argomenti potrebbe diventare complicato, specie visto che l'utente potrebbe indicarli in un ordine diverso da quello previsto.

Esaminiamo questo script:

#!/bin/bash getopts abc OPT echo "Hai indicato l'argomento $OPT !"

provando a lanciarlo si ottiene

$ ./script.sh -a Hai indicato l'argomento a !

Getopts ha effettuato il parsing di $@ (eventualmente si può indicare un'altra stringa come terzo argomento di getopts), e nel momento in cui ha verificato l'esistenza di una delle opzioni attese ("-a", "-b" e "-c", indicate dall' "abc" primo argomento di getopts) ha assegnato ad $OPT il nome di questa opzione.

Se eseguiamo

$ ./script.sh -z ./script.sh: illegal option -- z Hai indicato l'argomento ? !

il parametro "-z" non viene riconosciuto e viene segnalato un errore. E' possibile catturare l'errore verificando che il valore restituito da getopts non sia diverso da zero.

#!/bin/bash

OPTIND=1

echo $OPTIND getopts a:bc OPT echo "Hai indicato il parametro $OPT = $OPTARG !"

echo $OPTIND getopts a:bc OPT echo "Hai indicato il parametro $OPT = $OPTARG !"

$ ./script.sh -b -a 213 1 Hai indicato il parametro b = ! 2 Hai indicato il parametro a = 213 !

Il suddetto script esegue una prima volta getopts, legge il primo parametro indicato, "-b", assegna a $OPT quel valore; poi esegue di nuovo un'istruzione getopts, stavolta leggendo il parametro "-a", e assegnando a $OPT "-a" ed a $OPTARG il valore "213".

Come mai, pur se le istruzioni sono identiche, getopts cattura due parametri differenti? Il fatto si spiega perchè getopts legge il parametro indicato dalla variabile $OPTIND: visto che essa è inizialmente settata ad 1 (ricordarsi sempre di farlo), getopts legge "-b", e aumenta $OPTIND di una unità; dopodichè, getopts legge il secondo argomento (poichè $OPTIND ora equivale a 2) e ne stampa nome e valore.

Notare che se eseguo

$ ./script.sh -a 213 -b 1 Hai indicato il parametro a = 213 ! 3 Hai indicato il parametro b = !

getopts aumenta di 2 unità il valore di $OPTIND poichè il parametro "-a" contiene un argomento, "213"). E' da notare anche che nel momento in cui è stato richiamato getopts, la "a" del suo primo argomento era seguito da ":" ("getopts a:bc OPT"): i due punti indicano all'interprete che il parametro "-a" debba essere obbligatoriamente accompagnato da un argomento. Al contrario, se fossero stati omessi i due punti, l'argomento passato dopo "-a" sarebbe stato semplicemente ignorato, e $OPTARG sarebbe rimasta vuota.

Ecco un piccolo script che può mostrare un potenziale utilizzo di getopts:

#!/bin/bash

OPTIND=1

ERRMSG="ERRORE! Utilizzo: $0 [-a valore] [-b valore] [-c]";

if [ $# = 0 ] then echo $ERRMSG; exit 1; fi

while getopts a:b:c OPT do case $OPT in

  1. A=$OPTARG;;
  2. B=$OPTARG;;
  3. C=1;; ) echo $ERRMSG;; esac done

if [ $A ] then

echo "-a == $A"; fi

if [ $B ] then

echo "-b == $B"; fi

if [ $C ] then

echo "-c settato."; else

echo "-c non settato."; fi

lanciatelo e verificate.

  • HASH

hash [-r] [-p file] [nome]

Per ogni comando NOME viene ricercato il percorso in $PATH e viene memorizzato.Il semplice comando "hash" indica tutti i percorsi memorizzati, mentre l'opzione "-r" li cancella. Invece "-p" sostituisce il percorso di NOME col percorso FILE.

  • HELP

help [-s] [percorso]

Mostra delle informazioni sul programma specificato. Con "-s" visualizza la sintassi.

  • KILL

kill [-s segnale | -n numero_segnale | -segnale] [pid | nome_job] ... kill -l [numero_segnale | nome_segnale]

Manda un segnale (con "-s"; è possibile indicarne anche il numero con "-n") ad un job specificandone il nome o il pid. Con "-l", dato il numero del segnale restituisce il nome, e viceversa. Se il segnale non viene indicato, è sottinteso SIGTERM.

  • LOCAL

local [opzione] [nome[=valore] ...]

Dichiara ed assegna un valore alle variabili indicate. Queste variabili avranno visibilità soltanto all'interno della funzione in cui sono state dichiarate. Valgono per local le stesse opzioni di declare. Se non viene utilizzato all'interno di una funzione, restituisce un errore.

  • PWD

pwd [-LP]

Restituisce il percorso della directory corrente. Le opzioni servono per far visualizzare rispettivamente link simbolici e collegamenti fisici.

  • READ

read [-rs] [-t timeout] [-a nome_array] [-p prompt] [-n nchars] [-d delim] [name ...]

Legge una linea dallo standard input e assegna la prima parola alla prima variabile, la seconda parola alla seconda variabile e così via. Se non vengono indicate sufficienti variabili le parole rimanenti sono assegnate all'ultima. Se non viene specificata alcuna variabile, la riga letta è contenuta da $REPLY.

-a      Assegna le parole all'array specificato, indicizzandole a      
partire da 0
-d Il carattere con cui viene terminata la linea (predefinito
<newline>)
-n Read completa la linea dopo NCHARS caratteri invece di
aspettare la pressione di invio.
-p Permette di personalizzare il prompt
-r Backslash () non viene considerato come un carattere di
escape
-s In modalità silenziosa, i caratteri digitati non sono
mostrati
-t Attende l'input dell'utente per TIMEOUT secondi
  • RETURN

return [n]

Termina una funzione restituendo n (se n è omesso, restituisce lo stato dell'ultima istruzione).

  • SHIFT

shift [n]

I parametri posizionalida n+1 in poi diventano $1, $2, $3 e così via.

Es. echo $     # mostra gli ipotetici argomenti "a b c d e f"         
shift 2 # sposta "c" alla posizione $1, "d" a $2 e così via
echo $* # stampa "c d e f"

La variabile $0 non è coinvolta. Nel caso in cui n sia maggiore di $# non accade nulla. Se n non è definito equivale ad 1.

  • TEST

test espressione [ espressione ]

Restituisce 0 o 1 a seconda della valutazione di ESPRESSIONE (vedi ESPRESSIONI CONDIZIONALI).

  • TYPE

type [-atp] nome [nome ...]

Indica, se utilizzato senza argomenti, come NOME viene interpretato se usato come un comando. Con l'opzione -t, type stampa una parola tra alias, keyword, function, builtin, o file se NOME è, rispettivamente, alias, termine riservato della shell, funzione, builtin, o file del disco. Se viene utilizzata "-p" mostra il percorso del file se esso fa parte dei comandi eseguibili. L'opzione "-a" stampa tutte le info disponibili di NOME.

  • UNALIAS

unalias [-a] [nome ...]

Rimuove l'alias specificato da NOME. Con "-a" vengono rimossi tutti gli alias.

  • UNSET

unset [-fv] [nome ...]

Vengono rimosse le variabili specificate ("-v" è sottinteso). Utilizzando "-f" si fa riferimento a funzioni. Se alcune della variabili di shell quali RANDOM, SECONDS, LINENO vengono eliminate, perdono le loro proprietà, anche se vengono redichiarate.

REDIREZIONI

Gli input e gli output dei programmi possono essere redirezionati tramite degli appositi operatori. Vengono utilizzati inoltre dei canali detti "descrittori di file":

0       standard input  (la tastiera)                                  
1 standard output (il monitor)
2 standard error (il monitor)

Questi canali predefiniti si occupano dell'interazione con l'utente, ed è grazie ad essi che l'utente fornisce parametri e riceve dei risultati dai vari file.

  • REDIREZIONE DELL'INPUT

[n]<parola

Apre un file, indicato dall'espansione di PAROLA, in modalità lettura sullo standard input, o al descritto specificato da n. Da qui può poi essere utilizzato da altri programmi.

Es. cat < /etc/passwd # < equivale a 0< (la n si può sottintendere)

  • REDIREZIONE DELL'OUTPUT

[n]>parola

Viene aperto, come prima, un file, ma stavolta in modalità scrittura, e su di esso sono scritti i dati provenienti dallo standard output (o dal descrittore specificato da n). E'così possibile copiare su un file i risultati che un programma stampa sullo schermo.

Es. ls -l > ls.txt # > equivale a 1>

ls -l fileazzo 2> ls.txt # se il file "fileazzo" non esiste,

# il messaggio di errore va in ls.txt

Se il file da scriver non esiste viene creato, altrimenti viene cancellato e sovrascritto.

  • REDIREZIONE DELL'OUTPUT IN AGGIUNTA

[n]>>parola

Anche questo operatore apre (o crea) un file in modalità scrivibile, ma non ne cancella il contenuto nel caso esso contenga dati, ma aggiunge alla fine le righe indicategli.

  • REDIREZIONE DELLO STANDARD OUTPUT E STANDARD ERROR

E' possibile ricondurre contemporaneamente lo standard output e lo standard error verso un unico file.

&>word # Questa notazione è quella preferibile >&word

  • "HERE DOCUMENTS"

<<[-]parola here-document delimitatore

Con questa sintassi, viene indicato alla shell di leggere input dal codice corrente (oppure dal prompt) fino a quando non viene riscontrata una linea contenente PAROLA (che verrà quindi usata come DELIMITATORE). Nel caso PAROLA sia quotata, nessuna riga nell'"here-document" verrà espansa, e l'unquoting di PAROLA finirà nel nuovo DELIMITATORE. Nel caso si indicato il "-", tutte le tabulazioni iniziali nelle righe dell'"here-document" e del delimitatore vengono eliminate, dando quindi la possibilità di indentare il codice.

Per esempio, prova a digitare nell'ordine i seguenti comandi:

cat > spesa.txt << EOF mozzarella mortadella fodero (== lo sfilatino :-]) crocca cola EOF

Che è stato :-P ? Col primo comando ho prima creato il file vuoto SPESA.TXT, poi ho utilizzato l'HERE DOCUMENTS indicando EOF (End Of File) come parola per terminare la scrittura di quel file; le righe successive, seguite dalla pressione di invio, vengono rispettivamente scritte su SPESA.TXT, dopodichè quando digito EOF ritorna il prompt di shell... andando a fare "cat spesa.txt" ritroverò quello che ho digitato lì dentro :) In pratica, ho usato la shell come editor testuale (ma è utilissimo inserire procedure del genere in script vari).

  • DUPLICAZIONE DEI DESCRITTORI

[n]<&parola [n]>&parola

Con il primo si ottienela duplicazione dell'input, col secondo quella dell'output; è quindi possibile abbinare ad un unico descrittore dati provenienti da due sorgenti.

Es. find / -name *.txt -print > risultato.log 2>&1

Con questo comando tutti i riscontri positivi di find vanno a finire nel file risultato.log, mentre gli avvisi di errore (per esempio a causa di directory precluse all'utente) vengono contemporaneamente ridirezionati verso lo standard output; in pratica, standard output ed error vengono uniti (magiaaa :])

  • APERTURA DI DESCRITTORI IN LETTURA E SCRITTURA

[n]<>parola

In questo modo il file indicato dall'espansione di PAROLA viene aperto in lettura e scrittura sul descrittore n (0 se non è specificato).

THE END (?)

Ebbene, credo di aver spiegato tutto il minimo (?!) necessario per comprendere uno script shell (magari potrete decriptare quei famosi file ./configure così misteriosi :-) ).

Naturalmente le informazioni non finiscono qui... se volete avere l'onniscienza a riguardo guardatevi "man bash" :-PPP

Byez

by Domine

Mail: Questo indirizzo email è protetto dagli spambots. È necessario abilitare JavaScript per vederlo. WWW: http://www.autistici.org/domine/index.php IRC: Domine @ IRCNet, AzzurraNet