3 581
contributi
(possibili problemi con le espansioni di comando) |
|||
Riga 5: | Riga 5: | ||
Per l'uso interattivo si rimanda invece a [[Bash tips]]. | Per l'uso interattivo si rimanda invece a [[Bash tips]]. | ||
== Variabili | == Variabili == | ||
In Bash ogni variabile (di default) è trattata come una stringa. E il contenuto di una variabile si accede con <code>${nome}</code> oppure con la forma abbreviata <code>$nome</code>. | In Bash ogni variabile (di default) è trattata come una stringa. E il contenuto di una variabile si accede con <code>${nome}</code> oppure con la forma abbreviata <code>$nome</code>. | ||
Riga 72: | Riga 72: | ||
Si noti invece che usando <code>"$ARGUMENT"</code> (quotata) per una variabile contenente la stringa vuota, il comando leggerebbe lo stesso un argomento e potrebbe fallire. | Si noti invece che usando <code>"$ARGUMENT"</code> (quotata) per una variabile contenente la stringa vuota, il comando leggerebbe lo stesso un argomento e potrebbe fallire. | ||
==Variabili speciali== | ===Variabili speciali=== | ||
; <code>$?</code> : contiene il valore di uscita dell'ultimo comando o funzione. Il comando ha successo se restituisce zero, qualsiasi altro valore indica invece un codice di errore; | ; <code>$?</code> : contiene il valore di uscita dell'ultimo comando o funzione. Il comando ha successo se restituisce zero, qualsiasi altro valore indica invece un codice di errore; | ||
Riga 212: | Riga 212: | ||
===Quotare (racchiudere tra virgolette)=== | ===Quotare (racchiudere tra virgolette)=== | ||
Racchiudere tra virgolette (ossia quotare) ogni stringa è in genere raccomandabile e la scelta consigliata, così da ridurre drasticamente il numero di caratteri speciali, permettendo allo stesso tempo l'espansione delle variabili e dei comandi. I soli caratteri speciali sono <code>$</code>, <code>`</code> (ma non l'apice), <code>"</code> e <code>\</code> devono essere preceduti dal carattere di escape <code>\</code>. Le espansioni di percorso e tilda (*, ?, [...], ~, ... ) non sono possibili; mentre lo sono quelle di variabile e parametro (attraverso un <code>$</code> senza <code>\</code>), e quelle di comando (attraverso un <code>`</code> o un <code>$(</code> senza <code>\</code>). | Racchiudere tra virgolette (ossia quotare) ogni stringa è in genere raccomandabile e la scelta consigliata, così da ridurre drasticamente il numero di caratteri speciali, permettendo allo stesso tempo l'espansione delle variabili e dei comandi. I soli caratteri speciali sono <code>$</code>, <code>`</code> (ma non l'apice), <code>"</code> e <code>\</code>, che devono essere preceduti dal carattere di escape <code>\</code>. Le espansioni di percorso e tilda (*, ?, [...], ~, ... ) non sono possibili; mentre lo sono quelle di variabile e parametro (attraverso un <code>$</code> senza <code>\</code>), e quelle di comando (attraverso un <code>`</code> o un <code>$(</code> senza <code>\</code>). | ||
Riprendendo l'esempio e considerandolo per parti: | Riprendendo l'esempio e considerandolo per parti: | ||
Riga 225: | Riga 225: | ||
==Espansione di comando== | ==Espansione di comando== | ||
Si effettua racchiudendo un comando tra <code>$(...)</code>, oppure tra due apici gravi <code>`...`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>): | Consiste nel trasformare l'output di un comando qualsiasi (interno della shell, esterno, una funzione e anche forme composte) in argomenti per un altro comando, oppure nel valore da assegnare a una variabile. Si effettua racchiudendo un comando tra <code>$(...)</code>, oppure tra due apici gravi <code>`...`</code> (su tastiera con layout italiano: <code>Alt Gr + '</code>): | ||
<pre>$(comando)</pre> | <pre>$(comando)</pre> | ||
oppure, meno leggibile e sconsigliata: | oppure, meno leggibile e sconsigliata: | ||
Riga 232: | Riga 232: | ||
L'output del comando consiste in zero, una o più stringhe, in base agli spazi presenti nell'output prodotto e in maniera analoga all'espansione a cui sono soggette le variabili. Per trasformare l'output di un comando in una singola stringa è necessario che l'espansione di comando sia quotata, con l'eccezione dell'assegnazione a una variabile. | L'output del comando consiste in zero, una o più stringhe, in base agli spazi presenti nell'output prodotto e in maniera analoga all'espansione a cui sono soggette le variabili. Per trasformare l'output di un comando in una singola stringa è necessario che l'espansione di comando sia quotata, con l'eccezione dell'assegnazione a una variabile. | ||
Esempi di assegnazione: | |||
<pre> | <pre> | ||
oggi=$(date +%F) # | # assegna alla variabile $oggi la data in formato YYYY_MM_DD | ||
oggi=$(date +%F) # senza virgolette | |||
oggi="$(date +%F)" # equivalente a sopra (non servono nelle assegnazioni) | |||
# associo a testo il contenuto del file indicato da $file | |||
testo=$(cat $file) # SBAGLIATO! (se la variabile $file contiene spazi o caratteri speciali) | |||
testo=$(cat "$file") # le virgolette attorno alla variabile sono necessarie | |||
testo="$(cat "$file")" # equivalente a sopra | |||
</pre> | |||
Esecuzione dei comandi e passaggio come argomento del loro output: | |||
<pre> | |||
# stampa stati | # stampa stati | ||
echo "Login name: $(logname); Name: $(whoami); UID: $(id -ur); EUID: $(id -u); Groups: $(groups)" | echo "Login name: $(logname); Name: $(whoami); UID: $(id -ur); EUID: $(id -u); Groups: $(groups)" | ||
echo "OS: Debian GNU/Linux $(cat /etc/debian_version) ($(lsb_release -sc))" # uguale a $(lsb_release -sd) | echo "OS: Debian GNU/Linux $(cat /etc/debian_version) ($(lsb_release -sc))" # uguale a $(lsb_release -sd) | ||
echo "Kernel: $(uname) $(uname -r) ($(uname -v))" | echo "Kernel: $(uname) $(uname -r) ($(uname -v))" | ||
</pre> | |||
===Output con a capo finali=== | |||
Si noti che l'espansione di comando, come anche in '''sh''' (''POSIX'') non espande il comando a tutto l'output prodotto, ma omette sempre gli "a capo" finali. Se da una parte è utile nella maggior parte delle situazioni, può talvolta avere effetti collaterali difficili da prevedere. Si consideri per esempio: | |||
<pre>echo ciao > file_prova # scrive ciao (più un "a capo") nel file_prova | |||
testo=$(cat file_prova) # associa il contenuto (senza "a capo") a $testo | |||
echo "Lunghezza del file: ${#testo}" # non è la dimensione esatta del file | |||
echo "$testo" # stampa il contenuto di $testo (più un "a capo") | |||
</pre> | |||
{{Warningbox | Una variabile non può contenere il carattere ASCII numero 0, quindi per i file binari è sempre sbagliato accederli in questo modo. È sconsigliabile anche se non si è certi della loro dimensione, e se si è interessati soltanto alla prima riga si può utilizzare <code>read riga < file_prova</code>}} | |||
Un altro esempio, vogliamo associare il carattere "a capo" a una variabile: | |||
<pre> | |||
nuova_riga=" | |||
" # funziona, ma è brutto esteticamente e non permette l'indentazione | |||
nuova_riga=$'\n' # funziona (con Bash) ed è il modo consigliato | |||
# | # a titolo esemplicativo con l'espansione di comando | ||
nuova_riga=$(echo) # SBAGLIATO, $nuova_riga è vuota | |||
nuova_riga="$(echo)" # SBAGLIATO, come sopra | |||
nuova_riga=$(printf "\n") # SBAGLIATO, $nuova_riga è sempre vuota | |||
# una possibile soluzione... | |||
nuova_riga=$(printf "\nX") # $nuova_riga contiene "a capo" seguito da X | |||
nuova_riga=${nuova_riga%X} # $nuova_riga contiene "a capo" (la X è rimossa) | |||
# Attenzione che il carattere aggiunto dev'essere nell'output del comando | |||
nuova_riga=$(printf "\n")X # SBAGLIATO, $nuova_riga contiene solo X | |||
</pre> | </pre> | ||
Riga 386: | Riga 421: | ||
Cancella contenuto di un file: | Cancella contenuto di un file: | ||
$ :> xterm.txt | $ :> xterm.txt | ||
===Output dei comandi e carattere ASCII n. 0=== | |||
Una variabile non può contenere il carattere ASCII n. 0, che è usato per indicare la fine della stringa. Non potendo gestire direttamente il carattere ASCII n. 0, questo non può essere presente nell'espansione di un comando, ma dev'essere lasciato a comandi esterni mediante l'uso di una o più pipe. | |||
Infatti non esiste un modo di contenere il carattere ASCII n. 0 in nessuna posizione: | |||
<pre> | |||
var=$(printf '\000') # SBAGLIATO: $var è vuota | |||
var=$(printf '\000X') # SBAGLIATO: $var contiene solo X | |||
var=$(printf 'X\000X') # SBAGLIATO: $var contiene XX | |||
var="$(printf 'X\000X')" # SBAGLIATO: equivalente a sopra | |||
</pre> | |||
L'utilità di questo carattere si deve in particolare al fatto che nemmeno i file possono averlo nel proprio nome, mentre invece permettono caratteri jolly (*, ?, ...) come abbiamo già visto con le espansioni di percorso, e potrebbero contenere perfino il carattere "a capo". | |||
Uno script a titolo esemplificativo: | |||
<pre> | |||
# creo una directory e un file con "a capo" nel nome | |||
mkdir ./prova | |||
touch ./prova/"file contenente"$'\n'"a capo nel nome" | |||
# SBAGLIATO! (per via del nome del file particolare) | |||
num_file=$(find ./prova -type f | # stampo i file regolari nella directory, uno per riga | |||
wc -l) # conto il numero di righe | |||
echo "La directory prova contiene ${num_file} file" # restituisce 2 invece di 1 | |||
# forma corretta | |||
num_file=$(find ./prova -type f -print0 | # stampo il carattere ASCII n. 0 dopo ogni file | |||
tr -dc '\000' | # rimuovo tutti i caratteri ASCII diversi dal n. 0 | |||
wc -c) # conto il numero di caratteri | |||
echo "La directory prova contiene ${num_file} file" # restituisce 1 | |||
# pulizia | |||
rm -- ./prova/file*nome # elimino il file | |||
rmdir -- ./prova # elimino la directory (se vuota) | |||
</pre> | |||
Un abbinamento comune al comando esterno GNU <code>find</code> (dotato dell'opzione -print0) è il comando esterno GNU <code>xargs</code> (dotato dell'opzione -0): | |||
<pre> | |||
find /percorso -opzione1 ... -opzioneN -print0 | # trova file che soddisfano le condizioni date | |||
xargs -0 comando [ argomenti ... ] # passa questi file al comando | |||
</pre> | |||
Si leggano i rispettivi manuali per maggiori informazioni (<code>man find</code> e <code>man xargs</code>). | |||
== Debug integrato == | == Debug integrato == | ||
Riga 414: | Riga 494: | ||
|Verificata_da= | |Verificata_da= | ||
:[[Utente:S3v|S3v]] (versione in Bash tips) | :[[Utente:S3v|S3v]] (versione in Bash tips) | ||
:[[Utente:HAL 9000|HAL 9000]] | :[[Utente:HAL 9000|HAL 9000]] 21:46, 4 lug 2014 (CEST) | ||
|Estesa_da= | |Estesa_da= | ||
:[[Utente:S3v|S3v]] (versione in Bash tips) | :[[Utente:S3v|S3v]] (versione in Bash tips) |
contributi