[Lugge] Re: Bash Scripting problema...

  • From: asettico <asettico@xxxxxxxxxxxxxxx>
  • To: LUGGe <lugge@xxxxxxxxx>
  • Date: Sun, 29 May 2005 07:47:36 +0200

Andrea De Gaetano wrote:

Ciao a tutti... ho un problema con gli script in bash.
Premetto che sono ignorante in merito e ho quelle 2
orette di lavoro sulle spalle e basta di bash quindi
sono molto ignorante in materia..

Come dice il signor Spok, c'è una prima volta in tutto... :-) Se volessi approfondire, in tldp.org trovi almeno un paio di HOWTO ottimi.

Ho fatto questo script a fini puramente istruttivi.. Lista tutti i file in una directory e stampa i file
che il comando "file" riconosce come jpeg.
pare che il problema sia nell'if con il grep ma, non
riesco a risolverlo.. qualcuno puo' darmi una mano?
Grazie

Passiamo alla discussione del problema, partendo dalla soluzione più diretta, fino all'affinamento della procedura.

[ 1] #!/bin/bash
[ 2] [ 3] E_JPEG=\""JPEG\""
[ 4] for elemento in $(ls $PWD); do
[ 5] if [ -f $elemento ] ; then
[ 6] file $elemento > temp.txt
[ 7] if [ $(grep -i E_JPEG temp.txt) ] ; then
[ 8] echo "$elemento e' un jpeg"
[ 9] fi
[10] fi
[11] done

*Errore 1, riga 3* Non devi assegnare alla variabile E_JPEG anche i ", altrimenti questi caratteri verranno considerati come pattern di ricerca e, siccome il comando file non restituisce mai la stringa "JPEG", grep fallirà sempre. Usa: E_JPEG=JPEG

*Errore 2, riga 7*
Nel comando grep devi fare riferimento al _contenuto_ della variabile E_JPEG.
Usa: $E_JPEG

*Errore 3, riga 7*
La forma $(comando) viene sostituita dall'output dell'esecuzione di comando.
Se grep non trova occorrenze, non restituisce output, quindi il contenuto di
[ ] sarà una stringa vuota, che per convenzione è un valore falso: la
procedura non restituisce niente, correttamente.
Ma cosa succede quando grep trova qualcosa, cioè quando si incontra
un'immagine JPEG? tra [ ] viene messo l'output di grep, una stringa del tipo
        constitution_refit.jpg: JPEG image data, JFIF standard 1.01
che manda in errore if.
Siccome ti interessa sapere solo se l'output di file contiene la stringa
JPEG, non quale sia il valore della stringa restituita, puoi usare 2
soluzioni diverse:
- 1. Usa: "$(grep -i E_JPEG temp.txt)"
     Attenzione, non gli apici singoli ('), ma quelli doppi (").
- 2. Usa: if grep -iq E_JPEG temp.txt ; then
     L'opzione -q dice a grep di non restituire alcun output, perché verrà
usato solo il suo stato di uscita, che sarà 0 in caso di successo (stringa
JPEG trovata), che viene visto come valore vero da if, oppure 1 in caso di
fallimento (stringa JPEG non trovata), che viene visto come valore falso da if.
A prima vista sembra una soluzione logica controcorrente (0 vero, 1 falso),
ma ha un suo perché: per ogni comando esiste 1 e sola 1 condizione di
successo, segnalata dallo stato di uscita 0, mentre possono esserci motivi
diversi di fallimento, segnalati dal valore positivo dello stato di uscita e
dipendenti dal comando stesso. Generalizzando: 0 è vero, > 0 è falso.

Adesso passiamo alle ottimizzazioni.

*Ottimizzazione 1, riga 4*
Perché usare la variabile $PWD? ls usa di default la directory corrente se
non viene indicato alcun parametro.
Usa: for elemento in $(ls); do

*Ottimizzazione 2, riga 4*
Se vuoi usare come argomenti tutti i file della directory corrente, non
serve richiedere l'output del comando ls, ma basta usare l'espansione dei
wildcard.
Usa: for elemento in *; do

*Ottimizzazione 3, riga 5*
Non serve controllare che $elemento sia un file normale, tanto file
restituisce una valore coerente anche per le directory.
        $ file .
        .: directory
Semplicemente, verranno ignorate dall'if successivo.
Elimina pure quel test.

*Ottimizzazione 4, riga 6*
file può restituire la codifica mime, quindi un valore standard, mentre non
è garantito che la stringa restituita di default sia sempre quella.
Usa: file -i $elemento > temp.txt

*Ottimizzazione 5, riga 6 e 7*
Quando possibile, non utilizzare file temporanei. Sono più lenti che un
accesso alla memoria e vanno gestiti (cancellati alla fine e in tutte le
varie condizioni di errore ed interruzione). Inoltre, cosa molto importante,
potrebbe esistere già un file col nome scelto.
Usa: if file $elemento | grep -iq $E_JPEG ; then

*Ottimizzazione 6, riga 6 e 7*
Anziché cercare una stringa all'interno di un output di un comando, non
sarebbe molto più comodo e performante controllare il valore esatto? file
può restituire la codifica mime (ottimizzazione 4) e può restituire solo quella.
Usa: if [ $(file -bi $elemento) = "image/jpeg" ] ; then

*Lucidata 1, riga 7*
Se il blocco if contiene un solo comando, a me piace fare così:
per controllare se la condizione è vera
        [ "$(grep -i $E_JPEG temp.txt)" ] && echo "$elemento e' un jpeg"
per controllare se la condizione è falsa
        [ "$(grep -i $E_JPEG temp.txt)" ] || echo "$elemento non e' un jpeg"

Riassumento:

#!/bin/bash
E_JPEG=image/jpeg
for elemento in *; do
        [ $(file -bi $elemento) = $E_JPEG ] && echo "$elemento e' un jpeg"
done

Per il solo esempio riportato, si può anche scrivere
        file -Ni * | grep -w image/jpeg | \
        sed "s/\(.*\): image\/jpeg$/\1 e' un jpeg/"

Happy hacking! ;-)
--
asettico ~~ [ http://rossomaltese.it/ ]
GPG-keyid ~ [ 1024D/1CB926BA 2003-11-29 ]
http://keyserver.linux.it/pks/lookup?op=index&exact=on&search=asettico
========----------


Archivio delle e-mail postate in lista http://www.freelists.org/archives/lugge/

Prima di scrivere in m-list per favore leggi il regolamento http://www.lugge.net/index.php?mod=cosa_facciamo/gruppo_di_discussione
Modifica dell'account sulla lista LUGGe http://www.lugge.net/index.php?mod=cosa_facciamo/gruppo_di_discussione#list



Other related posts: