Guida avanzata di scripting Bash: Un'approfondita esplorazione dell'arte dello scripting di shell | ||
---|---|---|
Indietro | Capitolo 9. Variabili riviste | Avanti |
Bash supporta un numero sorprendentemente elevato di operazioni per la manipolazione delle stringhe. Purtroppo, questi strumenti mancano di organizzazione e razionalizzazione. Alcuni sono un sotto insieme della sostituzione di parametro, altri appartengono alle funzionalità del comando UNIX expr. Tutto questo si traduce in una sintassi dei comandi incoerente ed in una sovrapposizione di funzionalità, per non parlare della confusione.
Lunghezza della stringa
stringaZ=abcABC123ABCabc echo ${#stringaZ} # 15 echo `expr length $stringaZ` # 15 echo `expr "$stringaZ" : '.*'` # 15 |
Esempio 9-10. Inserire una riga vuota tra i paragrafi di un file di testo
#!/bin/bash # paragraph-space.sh # Inserisce una riga vuota tra i paragrafi di un file di testo con #+ spaziatura semplice. # Utilizzo: $0 <NOMEFILE LUNMIN=45 # Potrebbe rendersi necessario modificare questo valore. # Si assume che le righe di lunghezza inferiore a $LUNMIN caratteri #+ siano le ultime dei paragrafi. while read riga # Per tutte le righe del file di input... do echo "$riga" # Visualizza la riga. lun=${#riga} if [ "$lun" -lt "$LUNMIN" ] then echo # Aggiunge la riga bianca. fi done exit 0 |
Lunghezza della sottostringa verificata nella parte iniziale della stringa
$sottostringa è una espressione regolare.
$sottostringa è un'espressione regolare.
stringaZ=abcABC123ABCabc # |------| echo `expr match "$stringaZ" 'abc[A-Z]*.2'` # 8 echo `expr "$stringaZ" : 'abc[A-Z]*.2'` # 8 |
Indice
Numero di posizione in $stringa del primo carattere presente in $sottostringa che è stato verificato.
stringaZ=abcABC123ABCabc echo `expr index "$stringaZ" C12` # 6 # Posizione di C. echo `expr index "$stringaZ" 1c` # 3 # 'c' (in terza posizione) viene verificato prima di '1'. |
È quasi uguale alla funzione strchr() del C.
Estrazione di sottostringa
Estrae la sottostringa da $stringa iniziando da $posizione.
Se il parametro $stringa
è
"*" o "@",
allora vengono estratti i
parametri posizionali,
[1]
iniziando da $posizione
.
Estrae una sottostringa di $lunghezza caratteri da $stringa iniziando da $posizione.
stringaZ=abcABC123ABCabc # 0123456789..... # L'indicizzazione inizia da 0. echo ${stringaZ:0} # abcABC123ABCabc echo ${stringaZ:1} # bcABC123ABCabc echo ${stringaZ:7} # 23ABCabc echo ${stringaZ:7:3} # 23A # Sottostringa di tre caratteri. # È possibile indicizzare partendo dalla fine della stringa? echo ${stringaZ:-4} # abcABC123ABCabc # Restituisce l'intera stringa, come con ${parametro:-default}. # Tuttavia . . . echo ${stringaZ:(-4)} # Cabc echo ${stringaZ: -4} # Cabc # Ora funziona. # Le parentesi, o l'aggiunta di uno spazio, "preservano" il parametro negativo. # Grazie a Dan Jacobson per averlo evidenziato. |
Se il parametro $stringa
è
"*" o
"@",
vengono estratti un massimo di $lunghezza
parametri posizionali, iniziando da
$posizione
.
echo ${*:2} # Visualizza tutti i parametri iniziando dal secondo. echo ${@:2} # Come prima. echo ${*:2:3} # Visualizza tre parametri posizionali #+ iniziando dal secondo. |
Estrae $lunghezza caratteri da $stringa iniziando da $posizione.
stringaZ=abcABC123ABCabc # 123456789...... # L'indicizzazione inizia da 1. echo `expr substr $stringaZ 1 2` # ab echo `expr substr $stringaZ 4 3` # ABC |
Estrae $sottostringa dalla parte iniziale di $stringa, dove $sottostringa è una espressione regolare.
Estrae $sottostringa dalla parte iniziale di $stringa, dove $sottostringa è un'espressione regolare.
stringaZ=abcABC123ABCabc # ======= echo `expr match "$stringaZ" '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1 echo `expr "$stringaZ" : '\(.[b-c]*[A-Z]..[0-9]\)'` # abcABC1 echo `expr "$stringaZ" : '\(.......\)'` # abcABC1 # Tutte le forme precedenti danno lo stesso risultato. |
Estrae $sottostringa dalla parte finale di $stringa, dove $sottostringa è un'espressione regolare.
Estrae $sottostringa dalla parte finale di $stringa, dove $sottostringa è un'espressione regolare.
stringaZ=abcABC123ABCabc # ====== echo `expr match "$stringaZ" '.*\([A-C][A-C][A-C][a-c]*\)'` # ABCabc echo `expr "$stringaZ" : '.*\(......\)'` # ABCabc |
Rimozione di sottostringa
Toglie l'occorrenza più breve di $sottostringa dalla parte iniziale di $stringa.
Toglie l'occorrenza più lunga di $sottostringa dalla parte iniziale di $stringa.
stringaZ=abcABC123ABCabc # |----| # |----------| echo ${stringaZ#a*C} # 123ABCabc # È stata tolta l'occorrenza più breve compresa tra 'a' e 'C'. echo ${stringaZ##a*C} # abc # È stata tolta l'occorrenza più lunga compresa tra 'a' e 'C'. |
Toglie l'occorrenza più breve di $sottostringa dalla parte finale di $stringa.
Per esempio:
# Rinomina tutti i file in $PWD con suffisso "TXT" al suffisso "txt". # Esempio, "file1.TXT" diventa "file1.txt" . . . SUFF=TXT suff=txt for i in $(ls *.$SUFF) do mv -f $i ${i%.$SUFF}.$suff # Lascia inalterato tutto *tranne* la corrispondenza più breve #+ ad iniziare dalla parte destra della variabile $i . . . done ### Volendo, si poteva condensare in una "unica riga". # Grazie a Rory Winston. |
Toglie l'occorrenza più lunga di $sottostringa dalla parte finale di $stringa.
stringaZ=abcABC123ABCabc # || # |------------| echo ${stringaZ%b*c} # abcABC123ABCa # È stata tolta l'occorrenza più breve compresa #+ tra 'b' e 'c', dalla fine di $stringaZ. echo ${stringaZ%%b*c} # a # È stata tolta l'occorrenza più lunga compresa #+ tra 'b' e 'c', dalla fine di $stringaZ. |
È un operatore utile per generare nomi di file.
Esempio 9-11. Conversione di formato di file grafici e modifica del nome dei file
#!/bin/bash # cvt.sh: # Converte tutti i file immagine MacPaint, in una directory data, #+ nel formato "pbm". # Viene utilizzato l'eseguibile "macptopbm" del pacchetto "netpbm", #+ mantenuto da Brian Henderson (bryanh@giraffe-data.com). # Netpbm di solito è compreso nell'installazione standard della #+ maggior parte delle distribuzioni Linux. OPERAZIONE=macptopbm ESTENSIONE=pbm # Nuova estensione dei nomi dei file. if [ -n "$1" ] then directory=$1 # Se viene fornito il nome di una directory come #+ argomento dello script... else directory=$PWD # Altrimenti viene utilizzata la directory corrente. fi # Si assume che tutti i file immagine nella directory siano dei MacPaint, #+ con nomi aventi estensione ".mac" for file in $directory/* # Globbing dei nomi dei file. do nomefile=${file%.*c} # Toglie l'estensione ".mac" dal nome del file #+ ('.*c' verifica tutto tra '.' e 'c', compresi). $OPERAZIONE $file > "$nomefile.$ESTENSIONE" # Converte e redirige il file con una nuova #+ estensione. rm -f $file # Cancella i file originali dopo la conversione. echo "$nomefile.$ESTENSIONE" # Visualizza quello che avviene allo stdout. done exit 0 # Esercizio: # ---------- # Così com'è, lo script converte "tutti" i file presenti nella #+ directory di lavoro corrente. # Modificatelo in modo che agisca "solo" sui file con estensione ".mac". |
Esempio 9-12. Conversione di file in audio streaming nel formato ogg
#!/bin/bash # ra2ogg.sh: Converte i file in streaming audio (*.ra) al formato ogg. # Usa il programma "mplayer": # http://www.mplayerhq.hu/homepage # Affinché lo script funzioni potrebbe rendersi necessaria #+ l'installazione di codec appropriati. # Usa le librerie "ogg" e "oggenc": # http://www.xiph.org/ OFILEPREF=${1%%ra} # Toglie il suffisso "ra". OFILESUFF=wav # Suffisso dei file wav. OUTFILE="$OFILEPREF""$OFILESUFF" E_ERR_ARG=65 if [ -z "$1" ] # Deve essere fornito il nome del file da convertire. then echo "Utilizzo: `basename $0` [nomefile]" exit $E_ERR_ARG fi ########################################################################## mplayer "$1" -ao pcm:file=$OUTFILE oggenc "$OUTFILE" # oggenc aggiunge automaticamente la corretta estensione. ########################################################################## rm "$OUTFILE" # Cancella il file *.wav intermedio. # Se volete conservarlo, commentate la riga precedente. exit $? # Nota: # ---- # In un sito web cliccando sul file di streaming audio *.ram #+ solitamente viene scaricato solo l'URL del vero file audio, il file *.ra. # Si può allora usare "wget", o un programma analogo, #+ per scaricare direttamente il file *.ra. # Esercizi: # -------- # Così com'è lo script converte solamente i file con estensione *.ra. # Rendetelo più flessibile in modo che possa accettare anche file con #+ estensione *.ram o altra. # # Se siete veramente ambiziosi espandete lo script #+ in modo che esegua in automatico sia il download che la conversione dei file #+ di streaming audio. # Dato un URL, scarica in modalitàbatch gli streaming audio (usando "wget") #+ e li converte. |
Una semplice emulazione di getopt utilizzando i costrutti di estrazione di sottostringa.
Esempio 9-13. Emulare getopt
#!/bin/bash # getopt-simple.sh # Autore: Chris Morgan # Usato in Guida ASB con il suo consenso. semplice_getopt() { echo "semplice_getopt()" echo "I parametri sono '$*'" until [ -z "$1" ] do echo "Elaborazione parametro di: '$1'" if [ ${1:0:1} = '/' ] then tmp=${1:1} # Elinina le '/' iniziali . . . parametro=${tmp%%=*} # Estrae il nome. valore=${tmp##*=} # Estrae il valore. echo "Parametro: '$parametro', valore: '$valore'" eval $parametro=$valore fi shift done } # Passiamo tutte le opzioni a semplice_getopt(). semplice_getopt $* echo "verifica '$verifica'" echo "verifica2 '$verifica2'" exit 0 --- sh getopt_example.sh /verifica=valore1 /verifica2=valore2 I parametri sono '/verifica=valore1 /verifica2=valore2' Elaborazione parametro di: '/verifica=valore1' Parametro: 'verifica', valore: 'valore1' Elaborazione parametro di: '/verifica2=valore2' Parametro: 'verifica2', valore: 'valore2' verifica 'valore1' verifica2 'valore2' |
Sostituzione di sottostringa
Sostituisce la prima occorrenza di $sottostringa con $sostituto.
Sostituisce tutte le occorrenze di $sottostringa con $sostituto.
stringaZ=abcABC123ABCabc echo ${stringaZ/abc/xyz} # xyzABC123ABCabc # Sostituisce la prima occorrenza di 'abc' con 'xyz'. echo ${stringaZ//abc/xyz} # xyzABC123ABCxyz # Sostituisce tutte le occorrenze di 'abc' con 'xyz'. |
Se $sottostringa viene verificata all'inizio di $stringa, allora $sostituto rimpiazza $sottostringa.
Se $sottostringa viene verificata alla fine di $stringa, allora $sostituto rimpiazza $sottostringa.
stringaZ=abcABC123ABCabc echo ${stringaZ/#abc/XYZ} # XYZABC123ABCabc # Sostituisce l'occorrenza iniziale 'abc'con'XYZ'. echo ${stringaZ/%abc/XYZ} # abcABC123ABCXYZ # Sostituisce l'occorrenza finale 'abc' con 'XYZ'. |
Uno script Bash può ricorrere alle capacità di manipolazione delle stringhe di awk, come alternativa all'utilizzo dei propri operatori builtin.
Esempio 9-14. Modi alternativi di estrarre sottostringhe
#!/bin/bash # substring-extraction.sh Stringa=23skidoo1 # 012345678 Bash # 123456789 awk # Fate attenzione al diverso sistema di indicizzazione della stringa: # Bash numera il primo carattere della stringa con '0'. # Awk numera il primo carattere della stringa con '1'. echo ${Stringa:2:4} # posizione 3 (0-1-2), 4 caratteri di lunghezza # skid # L'equivalente awk di ${stringa:pos:lunghezza} è #+ substr(stringa,pos,lunghezza). echo | awk ' { print substr("'"${Stringa}"'",3,4) # skid } ' # Collegando ad awk un semplice comando "echo" gli viene dato un #+ input posticcio, in questo modo non diventa più necessario #+ fornirgli il nome di un file. exit 0 |
Per altro materiale sulla manipolazione delle stringhe negli script, si faccia riferimento alla Sezione 9.3 e all' importante sezione relativa all'elenco dei comandi expr. Per gli script d'esempio, si veda:
[1] | Questo vale sia per gli argomenti da riga di comando che per i parametri passati ad una funzione. |