Bash scripting - comandi essenziali: differenze tra le versioni
S3v (discussione | contributi) (- template "Versioni compatibili") |
m (rimosso template autori) |
||
Riga 160: | Riga 160: | ||
fi | fi | ||
</pre> | </pre> | ||
[[Categoria:Bash]][[Categoria:Bash_Scripting]] | [[Categoria:Bash]][[Categoria:Bash_Scripting]] |
Versione delle 18:02, 23 lug 2014
Bash scripting |
Sommario |
Comandi essenziali
I comandi introdotti in questa sezione sono descritti solo limitatamente alla loro sintassi base, così che il loro impiego nelle sezioni successive possa essere facilmente compreso.
La lettura della sezione può essere tralasciata, se si hanno già nozioni basilari di bash, ma la parte sui comandi di output serve anche a giustificare la scelta di printf
in luogo del più noto echo
come unico comando di output e a spiegarne brevemente la sintassi, almeno per le invocazioni più comuni.
Comandi di output: echo e printf
Il comando echo
è largamente diffuso in Bash per stampare delle stringhe su schermo, perché ha una sintassi più semplice di printf
e non risente delle stesse limitazioni della shell sh (POSIX), che interpreta ed espande i caratteri di escape (si legga la sezione dedicata) senza che ci sia un modo di stampare letteralmente una stringa (non nota a priori).
Tuttavia negli script l'uso di echo
non è sempre possibile, rendendo necessaria la conoscenza almeno basilare di printf
. In particolare, se si vuole stampare il contenuto di $var, non è sempre corretto scrivere:
echo -n "$var" # stampa senza a capo finale echo "$var" # stampa con a capo finale
perché $var potrebbe iniziare con il carattere "-
" ed essere una combinazione delle opzioni: -e, -E, -n.
Con echo
non esiste un modo che assicuri la stampa del contenuto di una variabile in ogni situazione possibile. E non sempre il contenuto è noto a priori: in presenza di espansioni, come vedremo poi, o di input dell'utente. Per non incorrere in errori difficili da riconoscere, echo
andrebbe usato soltanto nella shell interattiva, dove l'uso è più comodo, e printf
andrebbe preferito anche in Bash per gli script, perché ha una sintassi più robusta.
In questa guida d'ora in poi si farà riferimento soltanto a printf
.
Uso di printf
Sintassi: printf formato [ "stringa" ... ]
Gli usi più avanzati non sono trattati in questa guida, ma di seguito sono presentati alcuni esempi:
- stampa sullo schermo senza a capo finale
printf %s "stringa da stampare" printf %s "$var"
- stampa una riga vuota
printf \\n # corretto (doppio backslash) printf \n # ERRORE: stampa 'n' # tra virgolette printf "\\n" # corretto (doppio backslash) printf "\n" # corretto (singolo backslash) # tra apici printf '\\n' # ERRORE: stampa '\n' printf '\n' # corretto (singolo backslash)
- altri caratteri speciali nel formato (stesse considerazioni sull'uso di " e ')
printf \\t # tabulazione printf \\r # ritorno a inizio riga printf \\NNN # stampa il carattere ascii con codice in base 8
- stampa sullo schermo con a capo finale
printf %s\\n "stringa da stampare" printf %s\\n "$var"
- stampa con a capo prima e dopo
printf \\n%s\\n "stringa"
Mai stampare una stringa e ancora peggio una variabile senza farla precedere dal formato:
printf "stringa" # ERRORE: le sequenze speciali inizianti in \ e % verrebbero interpretate! printf "$var" # ERRORE: come sopra printf %s "stringa" # corretto printf %s "$var" # corretto
Per usi più complessi, anziché rendere più complicato il formato, è preferibile utilizzare più comandi printf
:
# funziona, ma è poco chiaro per chi non ne conosce la sintassi printf '%s\n\t%s %s\n' "Sintassi:" "$0" "[ arg ]" # più stringhe # equivalente, ma più leggibile: printf %s\\n "Sintassi:" printf '\t%s\n' "$0 [ arg ]"
Condizioni
Le condizioni nella shell dipendono dal valore di uscita (exit status) di un comando. Si considera successo un exit status corrispondente a 0, ed è equivalente a una condizione vera/soddisfatta, mentre fallimento un exit status con valori diversi da zero, e sono equivalenti a una condizione falsa/non soddisfatta.
Il significato dell'exit status di un comando (successo/fallimento) può essere invertito facendolo precedere da un punto esclamativo (!
).
Alcuni comandi hanno un exit status predeterminato:
:
o (equivalentemente)true
hanno un exit status sempre di zero (successo/vero);false
ha un exit status sempre diverso da zero (fallimento/falso).
Per esempio:
: # exit status 0 true # equivalente ! : # exit status diverso da 0 false # exit status diverso da 0 ! false # exit status 0
Espressioni booleane
Le espressioni booleane più basilari, ereditate da POSIX, si possono esprimere con i comandi test
e [
. L'unica differenza tra i due è che il secondo richiede ]
come ultimo argomento, ed è preferibile per questioni di leggibilità del codice. D'ora in poi infatti si considera soltanto [ ... ]
, e in questa sezione vengono descritte solo le forme più basilari. Per tutte le opzioni supportate si rimanda all'aiuto integrato (help test
).
Il comando [...]
restituisce un exit status di 0 (successo/vero) se la condizione contenuta all'interno è vera, e 1 (fallimento/falso) altrimenti. È molto utile all'interno di istruzioni più complesse, come if
per l'esecuzione condizionata e while
per eseguire cicli.
Confronti unari con stringhe (tipicamente l'espansione di variabile o parametro):
[ -z "$var" ]
: vero se var contiene una stringa di lunghezza zero o non è definita;[ -n "$var" ]
: vero se var contiene una stringa che non ha lunghezza zero.
Confronti binari tra stringhe (possono essere anche entrambe variabili):
[ "$var" = "stringa" ]
: vero se il contenuto di var è uguale alla stringa;[ "$var" != "stringa" ]
: vero se è diverso.
Confronti binari tra stringhe contenenti interi (possono essere anche entrambe variabili):
[ "$var" -gt valore ]
: (greater than) vero se l'intero contenuto nella variabile è maggiore del valore dato;[ "$var" -ge valore ]
: (greater or equal to) vero se l'intero contenuto nella variabile è maggiore o uguale al valore dato;[ "$var" -lt valore ]
: (lower than) vero se l'intero contenuto nella variabile è inferiore del valore dato.[ "$var" -le valore ]
: (lower or equal to) vero se l'intero contenuto nella variabile è inferiore o uguale al valore dato.
Se una delle due stringhe non è un intero, anche negativo, il confronto fallisce e può esserci la stampa di un messaggio d'errore sullo standard error. Per evitarlo va aggiunto 2> /dev/null
(il significato di tale redirezione sarà trattato in seguito). Per esempio:
[ "$var" -gt 0 ] 2> /dev/null # non stampa errori se $var non è un intero
Confronti unari con stringhe contenenti percorsi di file (percorso di default: directory corrente, se mancante):
[ -e "$var" ]
: vero se il file (file regolare, directory, link simbolico, fifo, socket, ... ) esiste;[ -f "$var" ]
: vero se il file esiste ed è un file regolare;[ -d "$var" ]
: vero se il file esiste ed è una directory.
Le espressioni più complesse si possono comporre utilizzando gli operatori logici &&
e ||
per aggregare più istruzioni [...]
, e le parentesi { ... ; }
per determinarne la priorità, come si vedrà nella parte sui blocchi di istruzioni.
Esecuzione condizionata
Per eseguire un blocco di comandi soltanto se una condizione è soddisfatta si utilizza if
, solitamente in combinazione con [...]
.
La sua sintassi base (in congiunzione con [...]
) è:
if [ espressione-booleana ]; then ... [ elif [ espressione-booleana ]; then ... ] ... [ else ... ... ] fi
Per esempio:
if [ -z "$var" ]; then printf %s\\n "La variabile var è nulla!" elif [ "$var" = "pluto" ]; then printf %s\\n "La variabile var contiene pluto" else printf %s\\n "La variabile var non è nulla e non contiene pluto, ma: ${var}" fi
Controllo degli errori
Si ricordi che if
accetta un comando qualsiasi come condizione, valutandone l'exit status ed eseguendo il ramo then
se ha successo, e quello elif
/else
immediatamente successivo (se presente) altrimenti. Quindi è un ottimo strumento anche per controllare che un comando venga eseguito senza errori, permettendo anche la terminazione immediata dello script:
if comando; then printf %s\\n "Comando riuscito!" else printf %s\\n "ERRORE: comando fallito!" # esci con errore (exit status 1) exit 1 fi
e se si è interessati al solo ramo else, basta utilizzare !
prima del comando:
if ! comando; then exit 1 fi