Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Capitolo 33. Miscellanea | Avanti |
Un "wrapper" è uno script di shell che incorpora una utility o un comando di sistema. Questo evita di dover digitare una serie di parametri che andrebbero passati manualmente a quel comando. [1] "Avvolgere" uno script attorno ad una complessa riga di comando ne semplifica l'invocazione. Questo è particolarmente utile con sed e awk.
Uno script sed o awk, di norma, dovrebbe essere invocato da riga di comando con sed -e 'comandi' o awk 'comandi'. Inserire un tale script in uno script Bash permette di richiamarlo in modo più semplice, rendendolo anche "riutilizzabile". In questo modo è anche possibile combinare le funzionalità di sed e awk, per esempio collegando con una pipe l'output di una serie di comandi sed a awk. Se salvato come file eseguibile può essere ripetutamente invocato, nella sua forma originale o modificata, senza l'inconveniente di doverlo ridigitare completamente da riga di comando.
Esempio 33-1. Shell wrapper
#!/bin/bash # Questo è un semplice script che rimuove le righe vuote da un file. # Nessuna verifica d'argomento. # # Sarebbe meglio aggiungere qualcosa come: # E_NOARG=65 # if [ -z "$1" ] # then # echo "Utilizzo: `basename $0` nome-file" # exit $E_NOARG # fi # È uguale a # sed -e '/^$/d' nomefile # invocato da riga di comando. sed -e /^$/d "$1" # '-e' significa che segue un comando di "editing" (in questo caso opzionale). # '^' indica l'inizio della riga, '$' la fine. # Verifica le righe che non contengono nulla tra il loro inizio e la fine, #+ vale a dire, le righe vuote. # 'd' è il comando di cancellazione. # L'uso del quoting per l'argomento consente di #+ passare nomi di file contenenti spazi e caratteri speciali. # Va notato che lo script, in realtà, non modifica il file di riferimento. # Se avete questa necessità, effettuate la redirezione dell'output. exit 0 |
Esempio 33-2. Uno shell wrapper leggermente più complesso
#!/bin/bash # "subst", uno script per sostituire un nome #+ con un altro all'interno di un file, #+ es. "subst Smith Jones letter.txt". ARG=3 # Lo script richiede tre argomenti. E_ERR_ARG=65 # Numero errato di argomenti passati allo script. if [ $# -ne "$ARG" ] # Verifica il numero degli argomenti (è sempre una buona idea). then echo "Utilizzo: `basename $0` vecchio-nome nuovo-nome nomefile" exit $E_ERR_ARG fi vecchio_nome=$1 nuovo_nome=$2 if [ -f "$3" ] then nome_file=$3 else echo "Il file \"$3\" non esiste." exit $E_ERR_ARG fi # Ecco dove viene svolto il lavoro principale. # ----------------------------------------------- sed -e "s/$vecchio_nome/$nuovo_nome/g" $nome_file # ----------------------------------------------- # 's' è, naturalmente, il comando sed di sostituzione, #+ e /modello/ invoca la ricerca di corrispondenza. # L'opzione "g", o globale, provoca la sostituzione di *tutte* #+ le occorrenze di $vecchio_nome in ogni riga, non solamente nella prima. # Leggete i testi riguardanti 'sed' per una spiegazione più approfondita. exit 0 # Lo script invocato con successo restituisce 0. |
Esempio 33-3. Uno shell wrapper generico che effettua una registrazione in un file di log
#!/bin/bash # Uno shell wrapper generico che effettua una/delle operazione/i #+ registrandola/e in un file di log. # Si devono impostare le variabili seguenti. OPERAZIONE= # Può essere una serie complessa di comandi, #+ per esempio uno script awk o una pipe . . . LOGFILE= # File di log. OPZIONI="$@" # Argomenti da riga di comando, se ce ne fossero, per operazione. # Registrazione. echo "`date` + `whoami` + $OPERAZIONE "$@"" >> $LOGFILE # Ora l'esecuzione. exec $OPERAZIONE "$@" # È necessario effettuare la registrazione prima dell'esecuzione. # Perché? |
Esempio 33-4. Uno shell wrapper per uno script awk
#!/bin/bash # pr-ascii.sh: Visualizza una tabella di caratteri ASCII. INIZIO=33 # Intervallo dei caratteri ASCII stampabili (decimali). FINE=125 echo " Decimale Esa Carattere" # Intestazione. echo " -------- --- ---------" for ((i=INIZIO; i<=FINE; i++)) do echo $i | awk '{printf(" %3d %2x %c\n", $1, $1, $1)}' # In questo contesto, il builtin Bash printf non funziona: # printf "%c" "$i" done exit 0 # Decimale Esa Carattere # -------- --- --------- # 33 21 ! # 34 22 " # 35 23 # # 36 24 $ # # . . . # # 122 7a z # 123 7b { # 124 7c | # 125 7d } # Redirigete l'output dello script in un file #+ o collegatelo con una pipe a "more": sh pr-asc.sh | more |
Esempio 33-5. Uno shell wrapper per un altro script awk
#!/bin/bash # Aggiunge la colonna specificata (di numeri) nel file indicato. ARG=2 E_ERR_ARG=65 if [ $# -ne "$ARG" ] # Verifica il corretto nr. di argomenti da riga #+ di comando. then echo "Utilizzo: `basename $0` nomefile numero-colonna" exit $E_ERR_ARG fi nomefile=$1 numero_colonna=$2 # Il passaggio di variabili di shell allo script awk incorporato #+ è un po' complicato. # Un metodo consiste nell'applicare il quoting forte alla variabile dello #+ script Bash all'interno dello script awk. # $'$VAR_SCRIPT_BASH' # ^ ^ # È ciò che è stato fatto nello script awk incorporato che segue. # Vedete la documentazione awk per maggiori dettagli. # Uno script awk che occupa più righe viene invocato con: awk ' ..... ' # Inizio dello script awk. # ----------------------------- awk ' { totale += $'"${numero_colonna}"' } END { print totale } ' "$nomefile" # ----------------------------- # Fine dello script awk. # Potrebbe non essere sicuro passare variabili di shell a uno script awk #+ incorporato, così Stephane Chazelas propone la seguente alternativa: # --------------------------------------- # awk -v numero_colonna="$numero_colonna" ' # { totale += $numero_colonna # } # END { # print totale # }' "$nomefile" # --------------------------------------- exit 0 |
Per quegli script che necessitano di un unico strumento tuttofare, un coltellino svizzero informatico, esiste Perl. Perl combina le capacità di sed e awk, e, per di più, un'ampia parte di quelle del C. È modulare e supporta qualsiasi cosa, dalla programmazione orientata agli oggetti fino alla preparazione del caffè. Brevi script in Perl si prestano bene ad essere inseriti in script di shell e si può anche dichiarare, con qualche ragione, che Perl possa sostituire completamente lo scripting di shell stesso (sebbene l'autore di questo documento rimanga scettico).
Esempio 33-6. Perl inserito in uno script Bash
#!/bin/bash # I comandi shell possono precedere lo script Perl. echo "Questa riga precede lo script Perl inserito in \"$0\"." echo "===============================================================" perl -e 'print "Questo è lo script Perl che è stato inserito.\n";' # Come sed, anche Perl usa l'opzione "-e". echo "===============================================================" echo "Comunque, lo script può contenere anche comandi di shell e di sistema." exit 0 |
È anche possibile combinare, in un unico file, uno script Bash e uno script Perl. Dipenderà dal modo in cui lo script verrà invocato quale delle due parti sarà eseguita.
Esempio 33-7. Script Bash e Perl combinati
#!/bin/bash # bashandperl.sh echo "Saluti dalla parte Bash dello script." # Qui possono seguire altri comandi Bash. exit 0 # Fine della parte Bash dello script. # ======================================================= #!/usr/bin/perl # Questa parte dello script deve essere invocata con l'opzione -x. print "Saluti dalla parte Perl dello script.\n"; # Qui possono seguire altri comandi Perl. # Fine della parte Perl dello script. |
bash$ bash bashandperl.sh Saluti dalla parte Bash dello script. bash$ perl -x bashandperl.sh Saluti dalla parte Perl dello script. |
[1] | Un certo numero di utility Linux sono, in effetti, dei shell wrapper. Alcuni esempi sono /usr/bin/pdf2ps, /usr/bin/batch e /usr/X11R6/bin/xmkmf. |