Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Avanti |
No programming language is perfect. There is not even a single best language; there are only languages well suited or perhaps poorly suited for particular purposes. | |
Herbert Mayer |
La conoscenza pratica dello scripting di shell è essenziale per coloro che desiderano diventare degli amministratori di sistema esperti, anche se mai avrebbero messo in preventivo di scrivere degli script. Occorre tener presente che quando viene avviata una macchina Linux, questa esegue gli script di shell contenuti nel file /etc/rc.d per ripristinare la configurazione del sistema ed attivarne i servizi. La comprensione dettagliata degli script di avvio è importante per analizzare il comportamento di un sistema e, se possibile, modificarlo.
Imparare a scrivere degli script non è difficile, perché possono essere costituiti da sezioni di piccole dimensioni ed è veramente esigua anche la serie di operatori ed opzioni specifiche [1] che è necessario conoscere. La sintassi è semplice e chiara, come quella necessaria per eseguire e concatenare utility da riga di comando, e sono poche anche le "regole" da imparare. Nella maggior parte dei casi, gli script di piccole dimensioni funzionano correttamente fin dalla prima volta che vengono eseguiti e non è complicata neanche la fase di debugging di quelli di dimensioni maggiori.
Uno script di shell è un metodo "rapido e grezzo" per costruire un prototipo di un'applicazione complessa. Far eseguire anche una serie ridotta di funzionalità tramite uno script di shell è spesso un utile primo passo nello sviluppo di un progetto. In questo modo si può verificare e sperimentare la struttura di un'applicazione e scoprire i principali errori prima di procedere alla codifica finale in C, C++, Java o Perl.
Lo scripting di shell è attento alla filosofia classica UNIX di suddividere progetti complessi in sezioni di minori dimensioni che svolgono un compito particolare, concatenando componenti e utility. Questo è considerato, da molti, un approccio migliore, o almeno esteticamente più piacevole per risolvere un problema, che utilizzare uno dei linguaggi di nuova generazione, come Perl, che offrono funzionalità per ogni esigenza, ma al prezzo di costringere a modificare il modo di pensare un progetto per adattarlo al linguaggio utilizzato.
Quando non usare gli script di shell
In compiti che richiedono un utilizzo intenso di risorse, specialmente quando la velocità è un fattore determinante (ordinamenti, hashing, ecc.)
In procedure che comprendono operazioni matematiche complesse, specialmente aritmetica in virgola mobile, calcoli in precisione arbitraria o numeri complessi (si usi C++ o FORTRAN)
È necessaria la portabilità (si usi, invece, il C o Java)
In applicazioni complesse dove è necessaria la programmazione strutturata (necessità di tipizzazione delle variabili, prototipi di funzione, ecc.)
In applicazioni critiche su cui si sta rischiando il tutto per tutto, o il futuro della propria azienda
In situazioni in cui la sicurezza è importante, dove occorre garantire l'integrità del sistema e proteggerlo contro intrusioni, cracking e vandalismi
In progetti costituiti da sotto-componenti con dipendenze interconnesse
Sono richieste operazioni su file di grandi dimensioni (Bash si limita ad un accesso sequenziale ai file, eseguito riga per riga e in un modo particolarmente goffo ed inefficiente)
È necessario il supporto nativo per gli array multidimensionali
Sono necessarie strutture di dati quali le liste collegate o gli alberi
È necessario generare o manipolare grafici o GUI
È necessario un accesso diretto all'hardware del sistema
È necessaria una porta o un socket I/O
È necessario l'utilizzo di librerie o interfacce per l'esecuzione di vecchio codice
In applicazioni proprietarie a codice chiuso (il codice sorgente degli script di shell è aperto e tutti lo possono esaminare)
Nel caso ci si trovi di fronte ad una o più delle eventualità appena descritte, occorrerà prendere in considerazione un linguaggio di scripting più potente -- che potrebbe essere Perl, Tcl, Python, Ruby -- o possibilmente un linguaggio compilato di alto livello, quale il C, C++ o Java. Anche in questo caso, però, eseguire dei prototipi di un'applicazione come script di shell potrebbe costituire un'utile base di sviluppo.
Sarà utilizzata Bash, acronimo di "Bourne-Again shell", e un po' un gioco di parole sull'ormai classica shell Bourne di Stephen Bourne. Bash è diventata uno standard de facto dello scripting di shell su ogni variante di sistema UNIX. La maggior parte dei principi spiegati in questo libro può essere applicata altrettanto bene allo scripting con altre shell, quale la Shell Korn, da cui Bash ha derivato alcune delle sue funzionalità [2] e la Shell C e le sue varianti (si faccia attenzione che programmare con la Shell C non è raccomandabile a causa di alcuni problemi ad essa inerenti, come evidenziato da Tom Christiansen in un post su Usenet nell'Ottobre 1993).
Quello che segue è un manuale sullo scripting di shell che sfrutta i numerosi esempi per illustrare le varie funzionalità della shell. Gli script di esempio funzionano correttamente -- sono stati verificati, per quanto sia stato possibile -- e alcuni di essi possono persino essere impiegati per scopi pratici. Il lettore può divertirsi con il codice degli esempi presenti nell'archivio dei sorgenti (nomescript.sh oppure nomescript.bash), [3] attribuirgli i permessi di esecuzione (con chmod u+rx nomescript), quindi eseguirli e vedere cosa succede. Se l'archivio dei sorgenti non dovesse essere disponibile, allora si ricorra ad un taglia-incolla dalle versioni HTML, pdf o testo. Si faccia attenzione che alcuni degli script riportati di seguito anticipano alcune funzionalità che non sono state ancora spiegate e questo richiede, per la loro comprensione, che il lettore dia uno sguardo ai capitoli successivi.
Se non altrimenti specificato, gli script di esempio che seguono sono stati scritti dall'autore.
[1] | Ad esse ci si riferisce come builtin, funzionalità interne alla shell. |
[2] | Molti degli elementi di ksh88 ed anche alcuni della più aggiornata ksh93 sono stati riuniti in Bash. |
[3] | Convenzionalmente, agli script creati da un utente che sono compatibili con la shell Bourne generalmente viene dato un nome con estensione .sh. Gli script di sistema, come quelli che si trovano nel file /etc/rc.d, non seguono questa regola. |