Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Avanti |
Utilizzate in modo appropriato, le variabili possono aumentare la potenza e la flessibilità degli script. Per questo è necessario conoscere tutte le loro sfumature e sottigliezze.
sono quelle variabili che determinano il comportamento dello script bash
$BASH
il percorso dell'eseguibile Bash
bash$ echo $BASH /bin/bash |
$BASH_ENV
variabile d'ambiente che punta al file di avvio di Bash, che deve essere letto quando si invoca uno script
$BASH_SUBSHELL
variabile che indica il livello della subshell. Si tratta di una nuova variabile aggiunta in Bash, versione 3.
Per il suo impiego vedi Esempio 20-1.
$BASH_VERSINFO[n]
un array di 6 elementi
contenente informazioni sulla versione Bash installata.
È simile a $BASH_VERSION
, vedi oltre,
ma più dettagliata.
# Informazioni sulla versione Bash: for n in 0 1 2 3 4 5 do echo "BASH_VERSINFO[$n] = ${BASH_VERSINFO[$n]}" done # BASH_VERSINFO[0] = 3 # Nr. della major version. # BASH_VERSINFO[1] = 00 # Nr. della minor version. # BASH_VERSINFO[2] = 14 # Nr. del patch level. # BASH_VERSINFO[3] = 1 # Nr. della build version. # BASH_VERSINFO[4] = release # Stato della release. # BASH_VERSINFO[5] = i386-redhat-linux-gnu # Architettura. # (uguale a $MACHTYPE). |
$BASH_VERSION
la versione Bash installata
bash$ echo $BASH_VERSION 3.00.14(1)-release |
tcsh% echo $BASH_VERSION BASH_VERSION: Undefined variable. |
Un buon metodo per determinare quale shell è in funzione è quello di verificare $BASH_VERSION. $SHELL potrebbe non fornire necessariamente una risposta corretta.
$DIRSTACK
il contenuto della locazione più alta dello stack delle directory (determinato da pushd e popd)
Questa variabile corrisponde al comando dirs, senonché dirs mostra l'intero contenuto dello stack delle directory.
$EDITOR
l'editor di testo predefinito invocato da uno script, solitamente vi o emacs.
$EUID
numero ID "effettivo" dell'utente
Numero identificativo dell'utente corrente corrispondente a qualsiasi identità egli abbia assunto, solitamente tramite il comando su.
|
$FUNCNAME
nome della funzione corrente
xyz23 () { echo "$FUNCNAME è in esecuzione." # xyz23 è in esecuzione. } xyz23 echo "NOME FUNZIONE = $FUNCNAME" # NOME FUNZIONE = # Valore nullo all'esterno della funzione. |
$GLOBIGNORE
un elenco di nomi di file da escludere dalla ricerca nel globbing
$GROUPS
i gruppi a cui appartiene l'utente corrente
È l'elenco (array) dei numeri id dei gruppi a cui appartiene l'utente corrente, così come sono registrati nel file /etc/passwd.
root# echo $GROUPS 0 root# echo ${GROUPS[1]} 1 root# echo ${GROUPS[5]} 6 |
$HOME
directory home dell'utente, di solito /home/nomeutente (vedi Esempio 9-15)
$HOSTNAME
In fase di boot, il comando hostname,
presente in uno script init, assegna il nome del sistema. Tuttavia
è la funzione gethostname()
che
imposta la variabile interna Bash $HOSTNAME
.
Vedi anche Esempio 9-15.
$HOSTTYPE
tipo di macchina
Come $MACHTYPE, identifica il sistema hardware, ma in forma ridotta.
bash$ echo $HOSTTYPE i686 |
$IFS
separatore di campo (internal field separator)
Questa variabile determina il modo in cui Bash riconosce i campi, ovvero le singole parole, nell'interpretazione delle stringhe di caratteri.
Il valore preimpostato è una
spaziatura (spazio,
tabulazione e ritorno a capo), ma può essere modificato,
per esempio, per verificare un file dati che usa la virgola
come separatore di campo. E' da notare che
$* utilizza il primo carattere
contenuto in $IFS
. Vedi
Esempio 5-1.
bash$ echo $IFS | cat -vte $ (Mostra le tabulazioni e visualizza "$" a fine-riga.) bash$ bash -c 'set w x y z; IFS=":-;"; echo "$*"' w:x:y:z (Legge i comandi da una stringa e assegna gli argomenti ai parametri posizionali.) |
(Grazie, S. C., per i chiarimenti e gli esempi.)
Vedi anche Esempio 15-37, Esempio 10-7 e Esempio 18-14 per un'istruttiva
dimostrazione sull'impiego di $IFS
.
$IGNOREEOF
ignora EOF: quanti end-of-file (control-D) la shell deve ignorare prima del logout
$LC_COLLATE
Spesso impostata nei file .bashrc o
/etc/profile, questa variabile controlla
l'ordine di collazione nell'espansione del nome del file e
nella ricerca di corrispondenza. Se mal gestita,
LC_COLLATE
può provocare risultati
inattesi nel globbing dei nomi
dei file.
Dalla versione 2.05 di Bash, il globbing dei nomi dei
file non fa più distinzione tra lettere minuscole e
maiuscole, in un intervallo di caratteri specificato tra
parentesi quadre. Per esempio, ls [A-M]*
restituisce sia File1.txt che
file1.txt. Per riportare il globbing
all'abituale comportamento, si imposti
|
$LC_CTYPE
Questa variabile interna controlla l'interpretazione dei caratteri nel globbing e nella ricerca di corrispondenza.
$LINENO
Variabile contenente il numero della riga dello script di shell in cui essa appare. Ha valore solo nello script in cui si trova. È utile in modo particolare nel debugging.
# *** INIZIO BLOCCO DI DEBUGGING *** ultimo_arg_cmd=$_ # Viene salvato. echo "Alla riga numero $LINENO, variabile \"v1\" = $v1" echo "Ultimo argomento eseguito = $ultimo_arg_cmd" # *** FINE BLOCCO DI DEBUGGING *** |
$MACHTYPE
tipo di macchina
Identifica il sistema hardware in modo dettagliato.
bash$ echo $MACHTYPE i486-slackware-linux-gnu |
$OLDPWD
directory di lavoro precedente ("OLD-print-working-directory", la directory in cui vi trovavate prima dell'ultimo comando cd)
$OSTYPE
nome del sistema operativo
bash$ echo $OSTYPE linux |
$PATH
i percorsi delle directory in cui si trovano i file eseguibili (binari), di solito /usr/bin/, /usr/X11R6/bin/, /usr/local/bin, ecc.
Quando viene dato un comando, la shell ricerca
automaticamente il percorso dell'eseguibile.
Questo è possibile perché tale percorso è
memorizzato nella variabile
d'ambiente $PATH
, che è un
elenco di percorsi possibili separati da : (due punti). Di
solito il sistema conserva la configurazione di
$PATH
nel file
/etc/profile e/o
~/.bashrc (vedi Appendice G).
bash$ echo $PATH /bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin |
PATH=${PATH}:/opt/bin aggiunge
la directory /opt/bin
ai percorsi predefiniti. Usato in uno script rappresenta un
espediente per aggiungere temporaneamente una directory a
$PATH
. Quando lo script termina viene
ripristinato il valore originale di $PATH
(questo perché un processo figlio, qual'è
uno script, non può modificare l'ambiente del processo
genitore, la shell).
La "directory di lavoro" corrente,
./, di solito per
ragioni di sicurezza, non è compresa in
|
$PIPESTATUS
Array contenente lo/gli exit status dell'ultima pipe eseguita in foreground (primo piano). È piuttosto interessante in quanto non fornisce necessariamente come risultato l'exit status dell'ultimo comando eseguito.
bash$ echo $PIPESTATUS 0 bash$ ls -al | comando_errato bash: comando_errato: command not found bash$ echo $PIPESTATUS 141 bash$ ls -al | comando_errato bash: comando_errato: command not found bash$ echo $? 127 |
Gli elementi dell'array $PIPESTATUS
sono gli exit status dei corrispondenti comandi
eseguiti nella pipe. $PIPESTATUS[0]
contiene l'exit status del primo comando della pipe,
$PIPESTATUS[1]
l'exit status del
secondo comando, e così via.
La variabile
I comandi precedenti, eseguiti in uno script, avrebbero prodotto il risultato atteso 0 1 0. Grazie a Wayne Pollock per la puntualizzazione e per aver fornito l'esempio precedente. |
La variabile
Chet Ramey attribuisce il risultato precedente al comportamento di ls. Se ls scrive in una pipe il cui output non viene letto, allora SIGPIPE lo termina, restituendo exit status 141. Altrimenti l'exit status è l'atteso 0. La stessa cosa vale per tr. |
|
L'opzione pipefail
può essere utile nei casi in cui
|
$PPID
Lo $PPID
di un processo non è
che l'ID di processo (pid
) del processo
genitore.
[1]
Lo si confronti con il comando pidof.
$PROMPT_COMMAND
Variabile che contiene un comando che deve essere eseguito
immediatamente prima della visualizzazione del prompt primario $PS1
.
$PS1
È il prompt principale, quello che compare sulla riga di comando.
$PS2
Prompt secondario. Compare quando è atteso un ulteriore input (il comando non è ancora terminato). Viene visualizzato come ">".
$PS3
Prompt di terzo livello, visualizzato in un ciclo select (vedi Esempio 10-29).
$PS4
Prompt di quarto livello. Viene visualizzato all'inizio di ogni riga di output quando lo script è stato invocato con l'opzione -x. Viene visualizzato come "+".
$PWD
Directory di lavoro (directory corrente)
È analoga al comando builtin pwd.
#!/bin/bash E_ERRATA_DIRECTORY=73 clear # Pulisce lo schermo. DirectoryDestinazione=/home/bozo/projects/GreatAmericanNovel cd $DirectoryDestinazione echo "Cancellazione dei vecchi file in $DirectoryDestinazione." if [ "$PWD" != "$DirectoryDestinazione" ] then # Evita di cancellare per errore una directory sbagliata. echo "Directory errata!" echo "Sei in $PWD, non in $DirectoryDestinazione!" echo "Salvo!" exit $E_ERRATA_DIRECTORY fi rm -rf * rm .[A-Za-z0-9]* # Cancella i file i cui nomi iniziano con un punto. # rm -f .[^.]* ..?* per cancellare file che iniziano con due o più punti. # (shopt -s dotglob; rm -f *) anche in questo modo. # Grazie, S.C. per la puntualizzazione. # I nomi dei file possono essere formati da tutti i caratteri nell'intervallo #+ 0 - 255, tranne "/". La cancellazione di file che iniziano con caratteri #+ inconsueti è lasciata come esercizio. # Altre eventuali operazioni. echo echo "Fatto." echo "Cancellati i vecchi file in $DirectoryDestinazione." echo exit 0 |
$REPLY
È la variabile preimpostata quando non ne viene fornita alcuna a read. È utilizzabile anche con i menu select. In questo caso, però, fornisce solo il numero che indica la variabile scelta, non il valore della variabile.
#!/bin/bash # reply.sh # REPLY è la variabile preimpostata per il comando 'read'. echo echo -n "Qual'è la tua verdura preferita?" read echo "La tua verdura preferita è $REPLY." # REPLY contiene il valore dell'ultimo "read" se e solo se #+ non è stata indicata alcuna variabile. echo echo -n "Qual'è il tuo frutto preferito?" read frutto echo "Il tuo frutto preferito è $frutto." echo "ma..." echo "Il valore di \$REPLY è ancora $REPLY." # $REPLY è ancora impostato al valore precedente perché #+ la variabile $frutto contiene il nuovo valore letto con "read". echo exit 0 |
$SECONDS
Numero di secondi trascorsi dall'inizio dell'esecuzione dello script.
#!/bin/bash TEMPO_LIMITE=10 INTERVALLO=1 echo echo "Premi Control-C per terminare prima di $TEMPO_LIMITE secondi." echo while [ "$SECONDS" -le "$TEMPO_LIMITE" ] do if [ "$SECONDS" -eq 1 ] then unita=secondo else unita=secondi fi echo "Questo script è in esecuzione da $SECONDS $unita." # Su una macchina lenta o sovraccarica lo script, talvolta, #+ potrebbe saltare un conteggio. sleep $INTERVALLO done echo -e "\a" # Beep! exit 0 |
$SHELLOPTS
l'elenco delle opzioni di shell abilitate. È una variabile in sola lettura
bash$ echo $SHELLOPTS braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs |
$SHLVL
Livello della shell, profondità di annidamento di Bash. [2] Se, da riga di comando $SHLVL vale 1, in uno script questo valore viene aumentato a 2.
Questa variabile non viene modificata dalle subshell. Si usi $BASH_SUBSHELL quando si ha la necessità di conoscere l'annidamento di una subshell. |
$TMOUT
Se la variabile d'ambiente
$TMOUT è impostata ad un valore
tempo
diverso da zero, il prompt della
shell termina dopo $tempo
secondi. Questo
provoca il logout.
Dalla versione Bash 2.05b è possibile utilizzare $TMOUT negli script in combinazione con read.
# Funziona negli script con Bash versione 2.05b e successive. TMOUT=3 # Imposta il prompt alla durata di tre secondi. echo "Qual'è la tua canzone preferita?" echo "Svelto, hai solo $TMOUT secondi per rispondere!" read canzone if [ -z "$canzone" ] then canzone="(nessuna risposta)" # Risposta preimpostata. fi echo "La tua canzone preferita è $canzone." |
Esistono altri metodi, più complessi, per implementare un input temporizzato in uno script. Una possibile alternativa è quella di impostare un ciclo di temporizzazione per segnalare allo script quando il tempo è scaduto. Ma anche così è necessaria una routine per la gestione di un segnale per catturare (trap) (vedi Esempio 29-5) l'interrupt generato dal ciclo di temporizzazione (fiu!).
Esempio 9-2. Input temporizzato
#!/bin/bash # timed-input.sh # TMOUT=3 Funziona anche questo, a partire dalle più recenti # versioni di Bash. TEMPOLIMITE=3 # In questo caso tre secondi. Può essere impostato #+ ad un valore diverso. VisualizzaRisposta() { if [ "$risposta" = TIMEOUT ] then echo $risposta else # Ho voluto tenere separati i due esempi. echo "La tua verdura preferita è $risposta" kill $! # Uccide la funzione AvvioTimer in esecuzione in #+ background perché non più necessaria. $! è il PID #+ dell'ultimo job in esecuzione in background. fi } AvvioTimer() { sleep $TEMPOLIMITE && kill -s 14 $$ & # Attende 3 secondi, quindi invia il segnale SIGALARM allo script. } Int14Vettore() { risposta="TIMEOUT" VisualizzaRisposta exit 14 } trap Int14Vettore 14 # Interrupt del timer (14) modificato allo scopo. echo "Qual'è la tua verdura preferita? " AvvioTimer read risposta VisualizzaRisposta # Ammettiamolo, questa è un'implementazione tortuosa per temporizzare #+ l'input, comunque l'opzione "-t" di "read" semplifica il compito. # Vedi "t-out.sh" più sotto. # Se desiderate qualcosa di più elegante... prendete in considerazione #+ la possibilità di scrivere l'applicazione in C o C++, #+ utilizzando le funzioni di libreria appropriate, come 'alarm' e 'setitimer'. exit 0 |
Un'alternativa è l'utilizzo di stty.
Esempio 9-3. Input temporizzato, un ulteriore esempio
#!/bin/bash # timeout.sh # Scritto da Stephane Chazelas #+ e modificato dall'autore del libro. INTERVALLO=5 # intervallo di timeout leggi_temporizzazione() { timeout=$1 nomevar=$2 precedenti_impostazioni_tty=`stty -g` stty -icanon min 0 time ${timeout}0 eval read $nomevar # o semplicemente read $nomevar stty "$precedenti_impostazioni_tty" # Vedi la pagina di manuale di "stty". } echo; echo -n "Come ti chiami? Presto! " leggi_temporizzazione $INTERVALLO nome # Questo potrebbe non funzionare su tutti i tipi di terminale. # Il timeout massimo, infatti, dipende dallo specifico terminale. #+ (spesso è di 25.5 secondi). echo if [ ! -z "$nome" ] # se il nome è stato immesso prima del timeout... then echo "Ti chiami $nome." else echo "Tempo scaduto." fi echo # Il comportamento di questo script è un po' diverso da "timed-input.sh". # Ad ogni pressione di tasto, la temporizzazione ricomincia da capo. exit 0 |
Forse, il metodo più semplice è quello di usare
read con l'opzione
-t
.
Esempio 9-4. read temporizzato
#!/bin/bash # t-out.sh # Ispirato da un suggerimento di "syngin seven" (grazie). TEMPOLIMITE=4 # 4 secondi read -t $TEMPOLIMITE variabile <&1 # ^^^ # In questo esempio, "<&1" è necessario per Bash 1.x e 2.x, # ma inutile per Bash 3.x. echo if [ -z "$variabile" ] # È nulla? then echo "Tempo scaduto, la variabile non è stata impostata." else echo "variabile = $variabile" fi exit 0 |
$UID
numero ID dell'utente
è il numero identificativo dell'utente corrente com'è registrato nel file /etc/passwd.
Rappresenta l'id reale dell'utente, anche nel caso abbia
assunto temporaneamente un'altra identità per mezzo di
su. $UID
è
una variabile in sola lettura e non può essere modificata
né da riga di comando né in uno script. È
il sostituto del builtin id.
Esempio 9-5. Sono root?
#!/bin/bash # am-i-root.sh: Sono root o no? ROOT_UID=0 # Root ha $UID 0. if [ "$UID" -eq "$ROOT_UID" ] # Il vero "root" avrà la compiacenza #+ di aspettare? then echo "Sei root." else echo "Sei un utente normale (ma la mamma ti vuol bene lo stesso)." fi exit 0 # ===================================================================== # # Il codice seguente non viene eseguito perché lo script è già terminato. # Un metodo alternativo per andare al fondo della questione: NOME_ROOT=root nomeutente=`id -nu` # Oppure... nomeutente=`whoami` if [ "$nomeutente" = "$NOME_ROOT" ] then echo "Rooty, toot, toot. Sei root." else echo "Sei solo un semplice utente." fi |
Vedi anche Esempio 2-3.
Le variabili
|
Parametri Posizionali
$0
,
$1
,
$2
, ecc.rappresentano i diversi parametri che vengono passati da riga di comando ad uno script, ad una funzione, o per impostare una variabile (vedi Esempio 4-5 e Esempio 14-15)
$#
numero degli argomenti passati da riga di comando, [3] ovvero numero dei parametri posizionali (vedi Esempio 33-2)
$*
Tutti i parametri posizionali visti come un'unica parola
" |
$@
Simile a $*, ma ogni parametro è una stringa tra apici (quoting), vale a dire, i parametri vengono passati intatti, senza interpretazione o espansione. Questo significa, tra l'altro, che ogni parametro dell'elenco viene considerato come una singola parola.
Naturalmente, " |
Esempio 9-6. arglist: Elenco degli argomenti con $* e $@
#!/bin/bash # arglist.sh # Invocate lo script con molti argomenti, come "uno due tre". E_ERR_ARG=65 if [ ! -n "$1" ] then echo "Utilizzo: `basename $0` argomento1 argomento2 ecc." exit $E_ERR_ARG fi echo indice=1 # Inizializza il contatore. echo "Elenco degli argomenti con \"\$*\":" for arg in "$*" # Non funziona correttamente se "$*" non è tra apici. do echo "Argomento nr.$indice = $arg" let "indice+=1" done # $* vede tutti gli argomenti come un'unica parola. echo "Tutto l'elenco come parola singola." echo indice=1 # Reimposta il contatore. # Cosa succede se vi dimenticate di farlo? echo "Elenco degli argomenti con \"\$@\":" for arg in "$@" do echo "Argomento nr.$indice = $arg" let "indice+=1" done # $@ vede gli argomenti come parole separate. echo "Elenco composto da diverse parole." echo indice=1 # Reimposta il contatore. echo "Eleco degli argomenti con \$* (senza quoting):" for arg in $* do echo "Argomento nr.$indice = $arg" let "indice+=1" done # $* senza quoting vede gli argomenti come parole separate. echo "Elenco composto da diverse parole." exit 0 |
Dopo uno shift, venendo a
mancare il precedente $1
, che
viene perso, $@
contiene i restanti
parametri posizionali.
#!/bin/bash # Da eseguire con ./nomescript 1 2 3 4 5 echo "$@" # 1 2 3 4 5 shift echo "$@" # 2 3 4 5 shift echo "$@" # 3 4 5 # Ad ogni "shift" viene perso il precedente $1. # Come conseguenza "$@" contiene i parametri rimanenti. |
All'interno degli script di shell, la variabile speciale
$@
viene utilizzata come strumento per filtrare
un dato input. Il costrutto cat "$@"
permette di gestire un input da uno script, dallo
stdin o da file forniti come parametri.
Vedi Esempio 15-21 e Esempio 15-22.
I parametri |
Esempio 9-7. Comportamento incoerente di
$*
e $@
#!/bin/bash # Comportamento non corretto delle variabili interne Bash "$*" e "$@", #+ dipendente dal fatto che vengano utilizzate o meno con il "quoting". # Gestione incoerente della suddivisione delle parole e del ritorno a capo. set -- "Il primo" "secondo" "il:terzo" "" "Il: :quinto" # Imposta gli argomenti dello script, $1, $2, ecc. echo echo 'IFS con il valore preimpostato, utilizzando "$*"' c=0 for i in "$*" # tra doppi apici do echo "$((c+=1)): [$i]" # Questa riga rimane invariata in tutti gli esempi. # Visualizza gli argomenti. done echo --- echo 'IFS con il valore preimpostato, utilizzando $*' c=0 for i in $* # senza apici do echo "$((c+=1)): [$i]" done echo --- echo 'IFS con il valore preimpostato, utilizzando "$@"' c=0 for i in "$@" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS con il valore preimpostato, utilizzando $@' c=0 for i in $@ do echo "$((c+=1)): [$i]" done echo --- IFS=: echo 'IFS=":", utilizzando "$*"' c=0 for i in "$*" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando $*' c=0 for i in $* do echo "$((c+=1)): [$i]" done echo --- var=$* echo 'IFS=":", utilizzando "$var" (var=$*)' c=0 for i in "$var" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando $var (var=$*)' c=0 for i in $var do echo "$((c+=1)): [$i]" done echo --- var="$*" echo 'IFS=":", utilizzando $var (var="$*")' c=0 for i in $var do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando "$var" (var="$*")' c=0 for i in "$var" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando "$@"' c=0 for i in "$@" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando $@' c=0 for i in $@ do echo "$((c+=1)): [$i]" done echo --- var=$@ echo 'IFS=":", utilizzando $var (var=$@)' c=0 for i in $var do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando "$var" (var=$@)' c=0 for i in "$var" do echo "$((c+=1)): [$i]" done echo --- var="$@" echo 'IFS=":", utilizzando "$var" (var="$@")' c=0 for i in "$var" do echo "$((c+=1)): [$i]" done echo --- echo 'IFS=":", utilizzando $var (var="$@")' c=0 for i in $var do echo "$((c+=1)): [$i]" done echo # Provate questo script con ksh o zsh -y. exit 0 # Script d'esempio di Stephane Chazelas, # con piccole modifiche apportate dall'autore. |
I parametri $@ e $* differiscono solo quando vengono posti tra doppi apici. |
Esempio 9-8. $*
e $@
quando
$IFS
è vuota
#!/bin/bash # Se $IFS è impostata, ma vuota, allora "$*" e "$@" non #+ visualizzano i parametri posizionali come ci si aspetterebbe. mecho () # Visualizza i parametri posizionali. { echo "$1,$2,$3"; } IFS="" # Impostata, ma vuota. set a b c # Parametri posizionali. mecho "$*" # abc,, mecho $* # a,b,c mecho $@ # a,b,c mecho "$@" # a,b,c # Il comportamento di $* e $@ quando $IFS è vuota dipende da quale #+ versione Bash o sh è in esecuzione. È quindi sconsigliabile fare #+ affidamento su questa "funzionalità" in uno script. # Grazie Stephane Chazelas. exit 0 |
Altri parametri particolari
$-
Opzioni passate allo script (utilizzando set). Vedi Esempio 14-15.
In origine era un costrutto ksh che è stato adottato da Bash, ma, sfortunatamente, non sembra funzionare in modo attendibile negli script Bash. Un suo possibile uso è quello di eseguire un'autoverifica di interattività. |
$!
PID (ID di processo) dell'ultimo job eseguito in background
LOG=$0.log COMANDO1="sleep 100" echo "Registra i PID dei comandi in background dello script: $0" >> "$LOG" # Possono essere così controllati e, se necessario, "uccisi". echo >> "$LOG" # Registrazione dei comandi. echo -n "PID di \"$COMANDO1\": " >> "$LOG" ${COMANDO1} & echo $! >> "$LOG" # PID di "sleep 100": 1506 # Grazie a Jacques Lederer, per il suggerimento. |
Uso di $!
per il controllo di un job:
possibile_job_bloccante & { sleep ${TIMEOUT}; eval 'kill -9 $!' &> /dev/null; } # Forza il completamento di un programma mal funzionante. # Utile, ad esempio, negli script init. # Grazie a Sylvain Fourmanoit per aver segnalato quest'uso creativo della variabile "!". |
O, in alternativa:
# Esempio di Matthew Sage. # Usato con il suo consenso. TIMEOUT=30 # Valore di timeout in secondi conto=0 possibile_job_bloccante & { while ((conto < TIMEOUT )); do eval '[ ! -d "/proc/$!" ] && ((conto = TIMEOUT))' # /proc directory dove si trovano informazioni sui processi #+ in esecuzione. # "-d" verifica se esiste (la directory). # Quindi attende che il job in questione venga individuato. ((conto++)) sleep 1 done eval '[ -d "/proc/$!" ] && kill -15 $!' # Se il job bloccante è in esecuzione, lo termina. } |
$_
Variabile speciale impostata all'ultimo argomento del precedente comando eseguito.
Esempio 9-9. Variabile underscore
#!/bin/bash echo $_ # /bin/bash # digitate solo /bin/bash per eseguire lo script. du >/dev/null # Non viene visualizzato alcun output del comando. echo $_ # du ls -al >/dev/null # Non viene visualizzato alcun output del comando. echo $_ # -al (ultimo argomento) : echo $_ # : |
$?
Exit status di un comando, funzione, o dello stesso script (vedi Esempio 23-7)
$$
ID di processo dello script. La variabile
$$
viene spesso usata negli script per
creare un nome di file temporaneo "univoco"
(vedi Esempio A-13, Esempio 29-6,
Esempio 15-28 e Esempio 14-26).
Di solito è più semplice che invocare
mktemp.
[1] | Naturalmente, il PID dello script in
esecuzione è |
[2] | In qualche modo analogo alla recorsività, in questo contesto annidamento indica un modello incorporato all'interno di un modello di dimensioni maggiori. Una delle definizioni di annidato, secondo l'edizione del 1913 del Webster's Dictionary, illustra perfettamente il concetto: "Una serie di scatole, casse, o simili, in scala di grandezza, ognuna inserita all'interno della successiva di dimensione maggiore." |
[3] | I termini "argomento" e "parametro" vengono spesso usati per indicare la stessa cosa. In questo libro hanno lo stesso, identico significato: quello di una variabile passata ad uno script o ad una funzione. |