Newsgroup: it.comp.os.linux.iniziare
Titolo: Aiuto su script bash

Salve a tutti.
ho una directory con circa 25000 files nominati in questo modo:
<nome_artista> - <nome_brano>
poichè sono presenti molti file per uno stesso artista ho avuto l'idea 
di creare uno script bash che analizzasse il nome di tutti i files e, a 
partire da questo, estraesse dal nome file il <nome_artista> escluso il 
trattino, creasse una cartella con il nome estratto e spostasse tale 
file nella cartella creata...e così via per ogni file.
il problema che incontro è per uqnto riguarda l'estrazione della stringa 
dal nome file (pattern matching)
qualcuno potrebbe aiutarmi ?
grazie

 file nella cartella creata...e così via per ogni file.
allora, un'idea di base e' questa:
#!/bin/sh
IFS='
' # visto che hai spazi nel nome dei file
for artista_brano in `ls`; do
  artista="$(echo "${artista_brano}"|awk -F ' - ' '{print $1}')"
  brano="$(echo "${artista_brano}"|awk -F ' - ' '{print $2}')"
  if [ ! -d "${artista}" ]; then # se non c' e' una cartella
    mkdir "${artista}"
  fi
  mv "${artista_brano}" "${artista}/${brano}" 
done
attenzione
non so se possa fungere su 25000 files, prova a farlo su gruppi piu'
piccoli di files.
-- 
quando l'assenza attende 
immaginare ancora una volta? 
vittima d'estate 
un'alba di ghiaccio

ZeD ha scritto:

grazie mille Zed per la rapidità della risposta...provo subito lo script 
  e ti faccio sapere.
se è possibile potresto spiegarmi (a scopo didattico) come funziona il 
pattern matching con awk che hai utilizzato ? ;)
grazie mille di nuovo !

 pattern matching con awk che hai utilizzato ? ;)
"pattern matching" e' una parola grossa
fondamentalmente mi sono limitato a usare awk dicendogli di usare come
"separatore di campo" i caratteri " - " (spazio, meno, spazio) e quindi di
stampare prima il primo campo (nel tuo caso l' artista) e dopo il secondo
campo (cioe' il brano)
man awk per maggiori informazioni
-- 
quando un cuore scompare 
vivere ancora! 
mancanza d'inverno 
un confine di primavera

 <nome_artista> - <nome_brano>
]zac[
nomefile="rino gaetano - aida"
artista=${nomefile/% - */}
brano=${nomefile/#* - /};
E' fondamentale che il separatore sia sempre uguale ' - ' ('  - ', '- ',
ecc. daranno problemi tipo errato spezzamento del nome file, spazi prima o
dopo del testo, ecc.).
P.S. Scaricati/consulta ' Advanced Bash-Scripting Guide ', una vero corso di
apprendimento a vari livelli degli script di shell.

 <nome_artista> - <nome_brano>
in casi tipo questi spesso scrivo un programma che scriva i comandi
shell, qui di seguito creo un file con un nome come i tuoi, e poi
scrivo il programma che mi serve
,----
| 22:46:22 sanmartino:~/tmp/del$ touch "owe oweqru ou qr - erio qweroiuo we4"
| 22:46:24 sanmartino:~/tmp/del$ ls
| owe oweqru ou qr - erio qweroiuo we4
| 22:47:18 sanmartino:~/tmp/del$ ls | awk -F" - " '{
|    printf("[ -d \"%s\" ] || mkdir \"%s\" ; mv \"%s\" \"%s\"/\"%s\"\n", $1, $1, $0, $1, $2 )}'
| [ -d "owe oweqru ou qr" ] || mkdir "owe oweqru ou qr" ; mv "owe oweqru ou qr - erio qweroiuo we4" "owe oweqru ou qr"/"erio qweroiuo we4"
| 22:47:22 sanmartino:~/tmp/del$ 
`----
la riga prima dell'ultimo prompt e' il comando di shell che serve nel
mio caso, dato che mi sembra vada bene pippo l'output del programma in
una nuova shell, e vedo con i successivi ls che cosa ho combinato
,----
| 22:47:22 sanmartino:~/tmp/del$ ls | awk -F" - " '{
| printf("[ -d \"%s\" ] || mkdir \"%s\" ; mv \"%s\" \"%s\"/\"%s\"\n",
| $1, $1, $0, $1, $2 )
| }' | sh
| 22:50:05 sanmartino:~/tmp/del$ ls
| owe oweqru ou qr
| 22:50:07 sanmartino:~/tmp/del$ ls owe\ oweqru\ ou\ qr/
| erio qweroiuo we4
| 22:50:34 sanmartino:~/tmp/del$ 
`----
direi che nel mio caso ho risolto (il -F" - " credo te l'abbiano gia'
spiegato, no?)
hth, ciao
-- 
e di sůbito parve giorno a giorno
essere aggiunto, come quei che puote
avesse il ciel d'un altro sole addorno

 scrivo il programma che mi serve
non voglio assolutamente offendere, ma mi sembra una gara a trovare il
modo piu' complicato per fare la cosa piu' semplice ^^;
non era piu' facile il programmino mio? (sebbene migliorabile, certo)
cioe', magari son io che son negato, ma mi sta venendo il mal di testa
solo a LEGGERLO il tuo script ^^;
-- 
quando un sogno sogna 
raccontare! 
in un fiume di metallo 
mancanza d'estate

 non era piu' facile il programmino mio? (sebbene migliorabile, certo)
<trot>
troppo facile
1:
#!/bin/sh
IFS='
' # visto che hai spazi nel nome dei file
for artista_brano in `ls`; do
  artista="$(echo "${artista_brano}"|awk -F ' - ' '{print $1}')"
  brano="$(echo "${artista_brano}"|awk -F ' - ' '{print $2}')"
  if [ ! -d "${artista}" ]; then # se non c' e' una cartella
    mkdir "${artista}"
  fi
  mv "${artista_brano}" "${artista}/${brano}"
done 
2:
dal prompt, digiti
% ls | awk -F" - " '
BEGIN { fmt="[ -d \"%s\" ] || mkdir \"%s\" ; mv \"%s\" \"%s\"/\"%s\"\n"}
      { printf( fmt, $1, $1, $0, $1, $2 )}' | sh 
% 
nel caso 1, fai partire 50000 processi awk, nel caso 2 ne fai partire
1, se sulla macchina gira pure qualcosaltro, la differenza c'e'...
l'approccio che in qs 3d ha proposto Giuseppe Della Bianca e' _molto_
migliore di quanto hai proposto, e probabilmente migliore del mio dal
punto di vista dei tempi di esecuzione, mentre la generazione di
comandi ha, imho, il vantaggio che puoi vedere cosa sara' eseguito
prima di decidere se mandarlo in esecuzione
</trot>


 
cript testato con successo ! :) Grazie mille !
non capisco solo a cosa serve queto comando all'interno dello script :


 non era piu' facile il programmino mio? (sebbene migliorabile, certo)
]zac[
Allora ti propongo, basandomi sulla tua proposta di usare IFS, una soluzione
che usa per il parsing solo comandi bash interni (quindi veloce), che è
generica e adattabile a varie situazioni:
#! /bin/bash
# prova
OLDIFS=$IFS
GFS=$'-'
IFS=$GFS
while read autore brano; do
    autore=${autore/% /}
    brano=${brano/* /}
    echo ^$autore^$brano^
done < <(IFS=$OLDIFS; ls *.txt)
IFS=$OLDIFS
*--- test ---*
ls *.txt:
aut1 - bran1.txt  aut1 - bran2.txt
aut ore1 - bran1.txt  aut ore1- bran2.txt
./prova:
^aut1^bran1.txt^
^aut1^bran2.txt^
^aut ore1^bran1.txt^
^aut ore1^bran2.txt^

 ' # visto che hai spazi nel nome dei file
man bash
/\<IFS\>
n
n
n
n
-- 
quando una foglia brucia 
incubo d'estate 
un fiume di luce

 IFS=$OLDIFS
non va
[zed@SwordFishII ~]$ l1 *.txt
Elio e le storie tese - Rock and roll.txt
Santa esmeralda - Don't let me be misunderstood.txt
[zed@SwordFishII ~]$ ./script.sh
^Elio e le storie tese^roll.txt^
^Santa esmeralda^misunderstood.txt^
con queste modifiche si', pero':
#!/bin/bash
IFS='
'
while read autore_brano; do
    autore=${autore_brano/ - */}
    brano=${autore_brano/* - /}
    echo ^$autore^$brano^
done < <(ls *.txt)
-- 
quando un sospiro nel vento arde 
un custode di luce 
ricordare forse d'estate

 non va
]zac[
Ehm, opss, non è sano confondere il comando 'da inizio stringa' ( # ) con
l'espressione regolare 'tutti i caratteri' ( * ):
errato>>>>     brano=${brano/* /}
giusto>>>>     brano=${brano/# /}
In sintesi la tokenizzazione era corretta, ma l'eliminazione degli spazi
dall'inizio del brano un tantinello eccessiva/errata.

 giusto>>>>     brano=${brano/# /}
mmm
dove posso trovare un testo "conciso e compendioso" a riguardo l'
espansione delle variabili in bash?
man bash -> Brace Expansion e' conciso, ma non lo capisco
se poi e' in italiano grasso che cola ^_^
-- 
quando l'onda nasce 
un dolore di neve 
conservare d'inverno

 se poi e' in italiano grasso che cola ^_^
Meglio evitare di cercarlo, trovandolo c'è il rischio di provocare una
glaciazione in pieno agosto ...

 glaciazione in pieno agosto ...
erh
comunque l'ABS e' DA TEMPO tradotta in italiano da quei sant'uomini dell'
ildp!
http://it.tldp.org/guide/abs/index.html
ora pero' voglio un po' di fresco!
-- 
quando il cuore nasconde 
in un bosco di ghiaccio 
vittima d'inverno

 ora pero' voglio un po' di fresco!
ehehe, aspetta, ho come la sensazione che fra poche settimane le temperature
caleranno ...