| 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. |