Newsgroup: it.comp.os.linux.sys
Titolo: Cambiare lettere con uno script bash

Ciao a tutti,
starei realizzando un piccol script bash che mi cambia automaticamente 
parti del nome dei file in una directory.
Ho scritto/scopiazzato la seguente funzione:
change_text () {
for x in `ls`
do
  if [[ -f $x ]] || [[ -d $x ]]; then
    newtext=`echo $x | sed s/$1/$2/g`
      if [ $newtext != $x ]; then
#       mv -i $x $newtext && echo "$x has been renamed to $newtext"
        echo "$x would have been renamed to $newtext"
      fi
  fi
done
}
(il commento serve per fare prove senza fare danni :-))
dopodiche' la richiamo:
change_text "&" "And"
change_text "'" "_"
change_text "," "_"
change_text "\!" ""
change_text "\?" ""
change_text ")" ""
change_text "(" "-"
change_text "\]" ""
change_text "\[" "-"
change_text "_-_" "-"
change_text "_-" "-"
change_text "-_" "-"
change_text "__" "_"
change_text "__" "_"
change_text "--" "-"
change_text "--" "-"
change_text "\._" "_"
change_text "_\." "_"
change_text "\.-" "-"
change_text "-\." "-"
change_text "\.\." "\."
change_text "MP3" "mp3"
change_text "JPG" "jpg"
change_text "_mp3" "\.mp3"
change_text "à" "a"
change_text "è" "e"
change_text "é" "e"
change_text "ì" "i"
change_text "ò" "o"
change_text "ù" "u"
change_text "ñ" "n"
E funziona bene fino alla riga
change_text "_mp3" "\.mp3"
poi passando alle lettere accentate non funziona e me le lascia cosi' 
come sono...
Avrei pensato di utilizzare il codice esadecimale, decimale o ottale 
indicato in:
man iso-8859-15
(ad esempio mettere Hex E8 al posto di "è")
ma non so come inserirlo nel mio script...
Grazie infinite a chi vorra' aiutarmi.
-- 
hamr...@toglimi.quipo.it
ANTI-SPAM: please cut "toglimi." for my real e-mail address.
Powered by Linux 2.6.26.5 on Debian Lenny
Registered Linux user #291116 
http://counter.li.org

 }
- Le variabili vanno quotate
- for x in `ls` e' una cosa da non fare MAI (o perlomeno 99,99% delle volte)
- il sed potrebbe avere problemi se $1 contiene caratteri di regex (.,*
[,],etc.)
- usa mv -- perche' altrimenti se hai un nome di file che inizia con "-" va
in palla
- esiste un meraviglioso programma che si chiama "rename" (anzi, ne esistono
piu' versioni). Se ce l'hai, usalo. Se non ce l'hai, installalo.
- se proprio vuoi usare bash, guarda qui:
http://wooledge.org:8000/BashFAQ/030

 volte) ...
No, poi proprio mai.
Nel caso malaugurato fosse proprio necessario fare ls 
allora quello che vuoi fare si fa così:
ls ... | while -r x
o così:
find ... -print0 | while read -r -d '' x 

 No, poi proprio mai.
Grazie degli ottimi suggerimenti, intanto aspetto sempre qualcuno che 
possa suggerirmi come sostituire "è" con il codice hex "E8" (oppure dec 
232, oct 350)...


 232, oct 350)...
Spunto:
echo -e '\0\x41'
Ciao

 No, poi proprio mai.
Anche perche' in questo caso e' equivalente a
for x in *



Cioe', "equivalente" nel senso che for x in * ottiene lo stesso risultato
voluto e non e' pericoloso come invece for x in `ls`.

antani scrisse:

No, assolutamente no
Il costrutto ``for x in *'' permette di trattare facilmente 
i nomi dei file contenenti spazi invece il costrutto 
``for x in `ls`'' rende impossibile ciò.
Però sono entrambi pericolosi nello stesso modo.
La pericolosità sta nel non mettere le virgolette
intorno alle variabili del ciclo e quindi non 
dipende dall'uso deprecabile di ``ls'' o dall'uso 
corretto ma con molti limiti del globbing.

 corretto ma con molti limiti del globbing.
Non diciamo cazzate. Il costrutto for x in `ls` e' pericoloso di suo perche'
la shell fa word splitting sull'output di ls e se ci sono nomi di file con
spazi vengono visti come piu' parole. for x in * NON ha questo problema.
Poi, se uno non quota le variabili, avra' ALTRI problemi, derivanti appunto
dal mancato quoting (non dall'uso di for x in *).

 perche' la shell fa word splitting...
Questo è il motivo per cui la sostituzione dei comandi non 
va usata in quel modo ed è un grave errore concettuale, ma 
non vedo quale sia la cosiddetta pericolosità di cui parli.
Il ciclo ``for x in *'' ha dei limiti e per questo non va 
usato negli script ma non vedo perchè non si possa digitare 
in una shell, è un comando perfettamente sicuro.
Tutta la questione è sull'uso della parola "sicuro"?
Finiamola, non vale la pena continuare.

 Finiamola, non vale la pena continuare.
Per quanto mi riguarda, se la discussione continua incontrera' (putroppo un
po' in ritardo) la sua conclusione piu' logica e naturale (e cioe' nel
killfile).

 perche' la shell fa word splitting sull'output di ls
IFS?
-- 
Vide



IFS settato a...?

 IFS settato a...?
New line... ls se non caga l'output a un terminale automaticamente aggiunge
un \n alla fine di ogni file.
PoC:
$ touch aa\ bb
$ touch ccc
$ ls
aa bb  ccc
$ for i in `ls`; do echo "123 -> $i"; done
123 -> aa
123 -> bb
123 -> ccc
$ IFS=$'\n'
$ for i in `ls`; do echo "123 -> $i"; done
123 -> aa bb
123 -> ccc
-- 
Vide



Premessa: i nomi dei file possono contenere \n, ma e' un caso raro e non
voglio utilizzarlo per confutare l'uso di IFS=$'\n' e di for i in `ls`.
Ammettiamo invece che usare IFS=$'\n' e for i in `ls` risolva i nostri
problemi. Ci sono varie obiezioni che si possono fare a questa soluzione. 
--- generalmente, all'interno del ciclo for non si fa echo "123 -> $i", ma
si fanno delle operazioni piu' o meno complicate. Non e' escluso che alcune
di queste operazioni richiedano che IFS abbia il suo valore standard, e
non "\n".
--- ammettiamo di avere questa situazione:
$ ls -1
b*
bar
b?r
foo
vogliamo iterare su tutti i file:
$ for i in `ls`; do echo "123 -> $i"; done
123 -> b*
123 -> bar
123 -> b?r
123 -> bar
123 -> bar
123 -> b?r
123 -> foo
Per "risolvere" questo problema, dobbiamo usare set -f, ma vedi il punto
successivo.
--- vogliamo iterare non su tutti i file, ma solo su tutti i .txt, e ne
abbiamo qualche migliaio nella directory.
$ for i in `ls *.txt`; do echo "123 -> $i"; done
-bash: /bin/ls: Argument list too long
(nota: il costrutto di cui sopra, a prescindere dal numero di file presenti,
non funziona se e' attivo set -f, perche' *.txt non viene espanso).
In conclusione: il modo migliore per evitare i problemi di cui sopra e'
usare il for con il corretto glob (che non ha quelle limitazioni, evita di
lanciare un processo extra, e gestisce anche i casi rari come i nomi di
file contenenti \n). 
Poi certo, magari il 90% delle volte le cose funzionano anche con IFS=$'\n'
e for i in `ls`, ma visto che c'e' un'alternativa piu' corretta e che non
ha problemi, non vedo perche' non bisognerebbe prendere l'abitudine di
usarla.

 New line... 
E se il nome del file contiene ritorni a capo?
PS settarlo a /NUL neanche funziona.

 voglio utilizzarlo per confutare l'uso di IFS=$'\n' e di for i in `ls`.
Grazie per l'esauriente spiegazione :)
-- 
Vide