Bash scripting - introduzione: differenze tra le versioni

Da Guide@Debianizzati.Org.
Vai alla navigazione Vai alla ricerca
mNessun oggetto della modifica
 
(3 versioni intermedie di 2 utenti non mostrate)
Riga 1: Riga 1:
{{Bash_scripting}}
{{Bash scripting}}
=Introduzione=
__TOC__
Lo scopo di questa guida, 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. Si cercherà anche di presentare le istruzioni in una sintassi il più possibile compatibile con la shell '''sh'''.
Lo scopo di questa guida, 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. Si cercherà anche di presentare le istruzioni in una sintassi il più possibile compatibile con la shell '''sh'''.


Riga 7: Riga 7:
Programmare con la shell è molto veloce, ed è indicato per risolvere un problema in fretta oppure per automatizzare una procedura eseguita manualmente su un proprio sistema, ma è semplice soltanto in apparenza. Al termine della lettura della guida spero sia chiaro quanto è invece difficile programmare bene e in modo robusto, per scrivere del codice che funzioni sempre in modo corretto in situazioni non note a priori. In particolare è necessario conoscere perfettamente il funzionamento delle variabili, almeno in relazione alle stringhe (il tipo di default), e di tutte le possibili espansioni.
Programmare con la shell è molto veloce, ed è indicato per risolvere un problema in fretta oppure per automatizzare una procedura eseguita manualmente su un proprio sistema, ma è semplice soltanto in apparenza. Al termine della lettura della guida spero sia chiaro quanto è invece difficile programmare bene e in modo robusto, per scrivere del codice che funzioni sempre in modo corretto in situazioni non note a priori. In particolare è necessario conoscere perfettamente il funzionamento delle variabili, almeno in relazione alle stringhe (il tipo di default), e di tutte le possibili espansioni.


Sono sconsigliati usi diversi dall'interazione con comandi di sistema o comunque presenti nella maggior parte delle installazioni, salvo sia solo per un proprio sistema, e si raccomanda invece l'impiego di altri linguaggi di programmazione, vista la complessità della sintassi dei comandi e la loro inefficienza in molte situazioni complesse.  Questa guida non tratta i comandi più avanzati, introdotti proprio da questa shell, come le redirezioni di processo e l'uso di array (indicizzati e associativi), per concentrarsi sugli aspetti più fondamentali
Sono sconsigliati usi diversi dall'interazione con comandi di sistema o comunque presenti nella maggior parte delle installazioni, salvo sia solo per un proprio sistema, e si raccomanda invece l'impiego di altri linguaggi di programmazione, vista la complessità della sintassi dei comandi e la loro inefficienza in molte situazioni complesse.  Questa guida non tratta i comandi più avanzati, introdotti proprio da questa shell, come le redirezioni di processo e l'uso di array (indicizzati e associativi), per concentrarsi sugli aspetti più fondamentali.


Per l'uso interattivo, per cui questa shell è ottima, si rimanda a [[Bash tips]]; e la lettura di questa guida può aiutare anche nella personalizzazione del proprio ambiente di lavoro, definendo per esempio delle funzioni in <code>~/.bashrc</code>. Si noti che l'espansione dello storico (''history expansion''), lì presentata e che qui manca, è attiva soltanto in modalità interattiva, mediante i caratteri speciali <code>!</code> e <code>^</code>.
Per l'uso interattivo, per cui questa shell è ottima, si rimanda a [[Bash tips]]; e la lettura di questa guida può aiutare anche nella personalizzazione del proprio ambiente di lavoro, definendo per esempio delle funzioni in <code>~/.bashrc</code>. Si noti che l'espansione dello storico (''history expansion''), lì presentata e che qui manca, è attiva soltanto in modalità interattiva, mediante i caratteri speciali <code>!</code> e <code>^</code>.


==Breve storia della shell==
== 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''').
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.
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 <code>/bin/sh</code> che era un link simbolico a <code>/bin/bash</code>), ma per questa funzione è stata rimpiazzata da '''dash''' (''Debian Almquist SHell''): più veloce, con meno dipendenze di librerie e aderente più strettamente a ''POSIX''.
Inizialmente '''bash''' era usata anche per gli script di sistema (con <code>/bin/sh</code> che era un link simbolico a <code>/bin/bash</code>), ma per questa funzione è stata rimpiazzata da '''dash''' (''Debian Almquist SHell''): più veloce, con meno dipendenze di librerie e aderente più strettamente a ''POSIX''.
Riga 20: Riga 20:
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'''.
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==
== Come creare uno script ==
Uno script, per poter essere eseguito come un eseguibile qualsiasi, in ambiente Unix e Unix-like deve:
Uno script, per poter essere eseguito come un eseguibile qualsiasi, in ambiente Unix e Unix-like deve:
* avere il bit di esecuzione attivo;
* avere il bit di esecuzione attivo;
Riga 31: Riga 31:
</pre>
</pre>


È consigliato inoltre di determinare esplicitamente il valore di ritorno (''exit status'') di uno script, facendolo terminare con l'istruzione <code>exit</code> 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.
È consigliato inoltre di determinare esplicitamente il valore di ritorno (''exit status'') di uno script, facendolo terminare con l'istruzione <code>exit</code> seguita dall'exit status, che è un valore intero compreso tipicamente tra 0 (l'unico valore che indica uno status di uscita dello script senza che siano avvenuti errori) 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 <code>if</code> oppure con gli operatori logici di concantenazione <code>&&</code> e <code>||</code>, che saranno introdotti.
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 <code>if</code> oppure con gli operatori logici di concatenazione <code>&&</code> e <code>||</code>, che saranno introdotti.


Fa eccezione l'istruzione <code>exec</code> 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.
Fa eccezione l'istruzione <code>exec</code> 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===
=== Commenti ===
È considerato commento tutto ciò che segue il carattere <code>#</code> fino alla nuova riga, purché <code>#</code> non sia racchiuso tra virgolette, apici o preceduto da <code>\</code>, in tal caso mantiene il suo valore letterale.
È considerato commento tutto ciò che segue il carattere <code>#</code> fino alla nuova riga, purché <code>#</code> non sia racchiuso tra virgolette, apici o preceduto da <code>\</code>, in tal caso mantiene il suo valore letterale.


Riga 44: Riga 44:
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.
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===
=== Il primo script ===
Esempio di classico programma che si limita a stampare "Hello world!" sullo schermo:
Esempio di classico programma che si limita a stampare "Hello world!" sullo schermo:
<pre>
<pre>
Riga 52: Riga 52:
</pre>
</pre>


===Rendere eseguibile uno script===
=== 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:
Una volta scritto lo script, non resta che attivarne il bit di esecuzione. Supponendo si chiami ''script.sh'', da un terminale dare:
<pre>
<pre>
Riga 63: Riga 63:
</pre>
</pre>


==Debug integrato==
== Debug integrato ==
'''Bash''', proprio come '''dash''' (la cui sintassi è limitata quasi soltanto alla shell POSIX), ha delle opzioni che ne consentono il debug.
'''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 <code>-n</code> è 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:
Invocando uno script con <code>-n</code> è 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:

Versione attuale delle 09:58, 13 nov 2015

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

Lo scopo di questa guida, 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. 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 conoscerne la sintassi si può consultarne il manuale (man nome-comando-esterno). La principale utilità dello scripting con la shell, dopo la garanzia della sua presenza su Debian e altre distribuzioni GNU/Linux, è 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.

Programmare con la shell è molto veloce, ed è indicato per risolvere un problema in fretta oppure per automatizzare una procedura eseguita manualmente su un proprio sistema, ma è semplice soltanto in apparenza. Al termine della lettura della guida spero sia chiaro quanto è invece difficile programmare bene e in modo robusto, per scrivere del codice che funzioni sempre in modo corretto in situazioni non note a priori. In particolare è necessario conoscere perfettamente il funzionamento delle variabili, almeno in relazione alle stringhe (il tipo di default), e di tutte le possibili espansioni.

Sono sconsigliati usi diversi dall'interazione con comandi di sistema o comunque presenti nella maggior parte delle installazioni, salvo sia solo per un proprio sistema, e si raccomanda invece l'impiego di altri linguaggi di programmazione, vista la complessità della sintassi dei comandi e la loro inefficienza in molte situazioni complesse. Questa guida non tratta i comandi più avanzati, introdotti proprio da questa shell, come le redirezioni di processo e l'uso di array (indicizzati e associativi), per concentrarsi sugli aspetti più fondamentali.

Per l'uso interattivo, per cui questa shell è ottima, si rimanda a Bash tips; e la lettura di questa guida può aiutare anche nella personalizzazione del proprio ambiente di lavoro, definendo per esempio delle funzioni in ~/.bashrc. Si noti che l'espansione dello storico (history expansion), lì presentata e che qui manca, è attiva soltanto in modalità interattiva, mediante i caratteri speciali ! e ^.

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 era un link simbolico a /bin/bash), ma per questa funzione è stata rimpiazzata da dash (Debian Almquist SHell): più veloce, con meno dipendenze di librerie e aderente 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 che indica uno status di uscita dello script senza che siano avvenuti errori) 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 concatenazione && 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