Bash scripting - introduzione

Versione del 23 lug 2014 alle 18:01 di HAL 9000 (discussione | contributi) (rimosso template autori)
Bash scripting

Sommario

  1. Introduzione
  2. Comandi essenziali
  3. Variabili (stringhe)
  4. Caratteri di escape, apici e virgolette
  5. Espansioni in stringhe quotate
  6. Espansioni non quotabili
  7. Istruzioni composte
  8. Funzioni
  9. File descriptor e redirezioni
  10. Segnali

Introduzione

Questa non è una guida completa, per la vastità dell'argomento. In particolare non sono trattati dei comandi importanti, alcuni introdotti proprio da questa shell:

  • di condizione ed esecuzione condizionata avanzata ([[, ((, case);
  • per effettuare il parsing degli argomenti (getopts);
  • di redirezione here-document e di processo;
  • modificatore declare (per interi, array e array associativi);
  • ecc...

Lo scopo della guida è invece, partendo dai concetti più basilari, di evidenziare i comportamenti più distintivi e facili da sbagliare di bash, con enfasi particolare sulle espansioni di stringhe, estremamente diverse da altri linguaggi di programmazione. Così da passare poi a guide più avanzate. Si cercherà anche di presentare le istruzioni in una sintassi il più possibile compatibile con la shell sh.

Quando si fa riferimento a comandi esterni, per conoscere la loro sintassi si può consultare il manuale (man nome-comando-esterno). La principale utilità dello scripting con la shell è proprio la semplicità di ampliarne le funzionalità richiamando altri eseguibili, quindi è consigliata anche la conoscenza dei principali (in particolare sulla gestione di file e directory).

Per l'uso interattivo della shell si rimanda invece a Bash tips. Si noti che l'espansione della history, che qui non è trattata, è attiva soltanto in modalità interattiva mediante i caratteri speciali ! e ^, che di default non hanno invece nessun significato particolare all'interno di uno script.

Breve storia della shell

GNU bash (Bourne-Again SHell) è una delle shell derivate da sh (la Bourne SHell, progettata da Stephen Bourne), la prima progettata per lo scripting. Bash è la scelta di default per l'uso interattivo su Debian e molte distribuzioni GNU/Linux, il che la rende una delle più diffuse, e incorpora molte nuove funzionalità rispetto a sh, alcune anche derivanti da altre shell (csh e ksh).

Quando si scrivono script con questa shell bisogna sapere che le nuove funzionalità comportano un costo, in termini di portabilità, rispetto agli script che si limitano alla sola sintassi prevista da POSIX (Portable Operating System Interface), una famiglia di standard che specificano come scrivere applicazioni funzionanti su tutti i sistemi Unix e che per la shell prescrive le sole istruzioni supportate da sh. Infatti uno script scritto per sh secondo lo standard POSIX sarà supportato anche da altri sistemi operativi della famiglia Unix e Unix-like che non hanno bash installato di default, come per esempio quelli della famiglia *BSD, a patto che anche i comandi esterni e le loro opzioni siano scelte secondo lo standard.

Inizialmente bash era usata anche per gli script di sistema (con /bin/sh che puntava a /bin/bash), ma per questa funzione è stata rimpiazzata da dash (Debian Almquist SHell): più veloce, con meno dipendenze di librerie e aderente molto più strettamente a POSIX.

Per quanto possibile in questa guida, in presenza di sintassi alternative, si tenderà a prediligere quella presente in POSIX e si segnalerà ogni volta che un'istruzione è presente unicamente in bash.

Come creare uno script

Uno script, per poter essere eseguito come un eseguibile qualsiasi, in ambiente Unix e Unix-like deve:

  • avere il bit di esecuzione attivo;
  • iniziare con due caratteri: #! (shebang).

Questo specifica che il file è uno script, ossia non è compilato e direttamente eseguibile, e va eseguito indirettamente invocandone l'interprete con il percorso e le eventuali opzioni scritte sulla stessa riga dello shebang.

Per scrivere uno script in bash basta quindi creare un file con la prima riga che faccia riferimento al percorso della shell:

#! /bin/bash

È consigliato inoltre di determinare esplicitamente il valore di ritorno (exit status) di uno script, facendolo terminare con l'istruzione exit seguita dall'exit status, che è un valore intero compreso tipicamente tra 0 (l'unico valore per successo) e 255. In assenza di tale istruzione il valore di ritorno dello script sarà determinato dall'exit status dell'ultimo comando eseguito.

Inoltre è bene sapere che l'esecuzione di uno script in bash, così come uno in sh (POSIX), di default non è interrotta in presenza di errori. È importante quindi controllare l'exit status dei comandi eseguiti, se possono fallire, con if oppure con gli operatori logici di concantenazione && e ||, che saranno introdotti.

Fa eccezione l'istruzione exec che, se seguita da un eseguibile esterno (anche un altro script), fa eseguire al processo corrente il nuovo eseguibile. Le istruzioni successive nello script non verranno eseguite, e il valore di uscita dello script è determinato da quello del nuovo eseguibile.

Commenti

È considerato commento tutto ciò che segue il carattere # fino alla nuova riga, purché # non sia racchiuso tra virgolette, apici o preceduto da \, in tal caso mantiene il suo valore letterale.

I commenti sono ovviamente ignorati dall'interprete, ma rendono più leggibile il codice.

Si noti che lo stessa shebang introduce una riga di commento, così da poter essere riconosciuta dal sistema grazie al sistema dei magic pattern e allo stesso tempo essere ignorata dall'interprete.

Il primo script

Esempio di classico programma che si limita a stampare "Hello world!" sullo schermo:

#! /bin/bash
printf %s\\n "Hello world!"
exit 0

Rendere eseguibile uno script

Una volta scritto lo script, non resta che attivarne il bit di esecuzione. Supponendo si chiami script.sh, da un terminale dare:

$ chmod +x script.sh

E dalla directory in cui si trova è possibile eseguirlo dal terminale con:

$ ./script.sh

Debug integrato

Bash, proprio come dash (la cui sintassi è limitata quasi soltanto alla shell POSIX), ha delle opzioni che ne consentono il debug.

Invocando uno script con -n è possibile effettuare un primitivo controllo di sintassi. Non vengono controllati comandi inesistenti e nemmeno le espansioni, ma può essere utile per verificare che i blocchi sono stati chiusi correttamente prima di eseguire lo script:

$ bash -n script.sh

Altre opzioni utili, che possono essere impiegate anche congiuntamente durante l'esecuzione:

  • -x stampa ogni comando prima di eseguirlo;
  • -v stampa l'intero blocco di codice che è stato letto (solo la prima volta);
  • -u interrompe lo script se si accede a una variabile mai assegnata;
  • -e interrompe lo script in caso di errore (se il comando non è controllato da un if, while o dalla concatenazione con ||).

E possono essere usate anche dopo lo shebang nella prima riga dello script. Per esempio:

#! /bin/bash -e