Pagina 1 di 2
batch - bash renamer
Inviato: ven 13 giu 2008, 11:33
da tiferet
Salve a tutti!
Da un po' di tempo ho la necessità di dover rinominare periodicamente parecchi file; fino ad adesso ho risolto utilizzando KRename , che però funziona solo con l'interfaccia grafica. Dato che devo amministrare anche il mio PC di casa, e al momento sono all'estero per studio, sapete se esiste un tool simile a riga di comando? St provando a realizzarne uno scritto in bash, ma l'impresa è più difficile di quello che pensassi, specie per l'inserzione di indici progressivi nel nome dei file.
Grazie.
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 11:37
da Paoletta
in che modo rinomini quei files?
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:06
da tiferet
beh, posso riportare lo script, ma è piuttosto lungo!
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:10
da targzeta
tiferet ha scritto:beh, posso riportare lo script, ma è piuttosto lungo!
Più che lo script, a noi serve capire:
1) come identifichi i file da rinominare (sono tutti sotto la stessa dir, hanno tutti un nome particolare, etc..)
2) come li vuoi rinominare
Spina
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:24
da tiferet
allora:
1) i file da rinominare devono essere tutti nella stessa directory e sono identificati con find
2) vorrei avere più possibilità di rinomina: inserire suffisso/prefisso, inserire una stringa in una posizione arbitraria, selezionare solo una parte del nome originale, convertire il nome del file in maiuscolo/minuscolo, inserire un indice etc.
In realtà lo script è quasi del tutto funzionante; l'unica funzione che non riesco ad implementare è quella per l'indice numerico:
Codice: Seleziona tutto
function createindex ()
{
# la funzione createindex crea un indice numerico col numero di cifre date
# il contatore è incrementato ad ogni chiamata
# sintassi: createindex stringa pos cifre start step
# dichiarazioni variabili locali
# {
local string=$1
local pos=$2
local num=$3
local index=""
# }
if [ "$i_start" -eq "-1" ]; then
i_start=${4:-"1"}
fi
if [ "$i_step" -eq "-1" ]; then
i_step=${5:-"1"}
fi
index=$i_start
while [[ $(echo -n $index | wc -m) -lt $num ]]; do
index=0$index
done
insertatpos $string $pos $index
let "i_start += i_step"
}
"insertatpos" è un'altra funzione che serve ad inserire una stringa in una data posizione (nome originale, eh?); il problema è che sebbene i_start e i_step non siano variabili locali, quando il programma esce dalla funzione createindex e ritorna nel ciclo for di rinomina, queste due variabili riassumono il valore iniziale, ossia -1, e quindi ottengo sempre lo stesso indice.
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:36
da targzeta
Io ho tolto tutte le " nei numeri, in questo modo:
Codice: Seleziona tutto
function insertatpos ()
{
return;
}
function createindex ()
{
local string=$1
local pos=$2
local num=$3
local index=""
if [ $i_start -eq -1 ]; then
i_start=${4:-1}
fi
if [ $i_step -eq -1 ]; then
i_step=${5:-1}
fi
index=$i_start
while [[ $(echo -n $index | wc -m) -lt $num ]]; do
index=0$index
done
insertatpos $string $pos $index
let i_start+=i_step
}
i_start=-1;
i_step=-1;
createindex;
echo $i_start $i_step
provandolo ho ottenuto:
2 1
e mi sembra che sia andato tutto bene no?
Spina
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:50
da tiferet
giusto, ma a me continua a non funzionare. A questo punto devo pensare che ci sia un errore da qualche parte nel resto dello script. Controllerò meglio!
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:52
da targzeta
manda lo script allora.
Spina
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 12:57
da tiferet
Codice: Seleziona tutto
#!/bin/bash -x
# The bash/sh interpreter
# bmv, script bash/sh creato il 01 - March - 2008
# =======================================================================================
# inizio dichiarazione delle funzioni
# =======================================================================================
function dohelp ()
{
# se mi chiedi aiuto o non sai come usarmi, ti spiego
echo "$(basename $0) v1.0
Questo script unisce le funzionalità di \"mv\" e \"find\" e offre funzionalità simili a quelle
offerte da alcuni programmi di rinomina di massa come KRename.
Utilizzo:
$(basename $0) [opzioni] [start_path] [end_path] [find_opt]
è possibile fornire le seguenti opzioni:
-d, il nome del file è convertito in minuscolo
-U, il nome del file è convertito in maiuscolo
-f, tutte le iniziali del nome del file sono poste in maiuscolo
-u, la lettera iniziale del nome del file sono poste in maiuscolo
-i pos:string, inserisce alla posizione \"pos\" la stringa \"string\"
-c start:end, il nome del file è tagliato fra \"start\" e \"end\"
-p string, inserisce il prefisso \"string\"
-a string, inserisce il suffisso \"string\"
-s orig:sub, sostituisce la stringa \"orig\" con la stringa \"sub\"
-f filename, i file sono rinominati in base ai nomi riportati nel file \"filename\",
uno per riga
start_path, il percorso iniziale
end_path, il percorso finale
find_opt, opzioni da passare al comando \"find\"
"
exit 0
}
function doconf ()
{
# se mi chiedi la configurazione attuale, te la do senza discutere
echo "Spiacente, nessuna configurazione disponibile!"
echo ""
exit 0
}
function alldowncase () # -d
{
# la funzione alldowncase restituisce la stringa in ingresso con tutte le lettere in
# minuscolo
# dichiarazioni variabili locali
# {
local string=$1
# }
echo $string | tr '[:upper:]' '[:lower:]'
}
function alluppercase () # -U
{
# la funzione alluppercase restituisce la stringa in ingresso con tutte le lettere in
# maiuscolo
# dichiarazioni variabili locali
# {
local string=$1
# }
echo $string | tr '[:lower:]' '[:upper:]'
}
function firstuppercase () # -u
{
# la funzione firstuppercase restituisce la stringa in ingresso con la prima lettera in
# maiuscolo
# dichiarazioni variabili locali
# {
local string=$1
local first=$(echo $string | cut -c1 | tr '[:lower:]' '[:upper:]')
local others=$(echo $string | cut -c2-)
# }
echo $first$others
}
function allfirstupc () # -f
{
# la funzione firstuppercase restituisce la stringa in ingresso con la prima lettera
# di ogni parola in maiuscolo
# dichiarazioni variabili locali
# {
local string=$1
local words=""
local out_string=""
# }
# conto quante parole sono presenti in $1
words=$(echo $string | wc -w)
# inizializzo il contatore
i=1
# creo la stringa finale
while [[ $i -le $words ]]; do
out_string="$out_string $(firstuppercase `echo $1 | cut "-d " -f$i`)"
let "i += 1"
done
echo $out_string
}
function insertatpos () # -i {pos:string}
{
# la funzione insertatpos inserisce nella posizione specificata un determinata stringa
# sintassi: insertatpos stringa posizione inserzione
# dichiarazioni variabili locali
# {
local string=$1
local pos=$2
local in_string=$3
local trunk1=""
local trunk2=""
# }
if [ "$pos" == "start" ]; then
prepend $string $in_string
elif [ "$pos" == "end" ]; then
append $string $in_string
else
let "pos -= 1"
trunk1=$(echo $string | cut -c1-$pos)
trunk2=$(echo $string | cut -c$((($pos + 1)))-)
echo $trunk1$in_string$trunk2
fi
}
function cutatpos () # -C {start:end}
{
# la funzione cutatpos restituisce uno spezzone della stringa in ingresso
# sintassi cutatpos stringa start end
# dichiarazioni variabili locali
# {
local string=$1
local start=$2
local end=$3
# }
if [ "$start" == "start" -a "$end" == "end" ]; then
echo $string
elif [ "$start" == "start" ]; then
echo $string | cut -c-$end
elif [ "$end" == "end" ]; then
echo $string | cut -c$start-
else
echo $string | cut -c$start-$end
fi
}
function prepend () # -p {string}
{
# la funzione prepend inserisce una stringa all'inizio della stringa in ingresso
# sintassi: prepend stringa_base stringa_pre
# dichiarazioni variabili locali
# {
local string=$1
local pre_str=$2
# }
echo $pre_str$string
}
function append () # -a {string}
{
# la funzione append inserisce una stringa alla fine della stringa in ingresso
# sintassi: append stringa_base stringa_post
# dichiarazioni variabili locali
# {
local string=$1
local post_str=$2
# }
echo $string$post_str
}
function createindex ()
{
# la funzione createindex crea un indice numerico col numero di cifre date
# il contatore è incrementato ad ogni chiamata
# sintassi: createindex stringa pos cifre start step
# dichiarazioni variabili locali
# {
local string=$1
local pos=$2
local num=$3
local index=""
# }
if [ "$i_start" -eq -1 ]; then
i_start=${4:-1}
fi
if [ "$i_step" -eq -1 ]; then
i_step=${5:-1}
fi
index=$i_start
while [[ $(echo -n $index | wc -m) -lt $num ]]; do
index=0$index
done
insertatpos $string $pos $index
let i_start+=i_step
}
function substitute () # -s {orig:subs}
{
# la funzione substitute restituisce la stringa in ingresso in cui tutte le occorrenze
# di un pattern sono sostituite con un altro pattern
# sintassi substitute stringa orig sub
# dichiarazioni variabili locali
# {
local string=$1
local orig=$2
local subs=$3
# }
echo $string | sed -r s/$orig/$subs/g
}
function filelist () # -f filename
{
# la funzione filelist serve per rinominare vari file, ordinati numericamente, sulla
# base di un file che contiene un nome per ciascuna riga
# dichiarazioni variabili locali
# {
local list=$1
# }
echo $(head -n$file_index $list | tail -n1)
}
function extargs ()
{
# la funzione extargs ha lo scopo di fornire alle funzioni i parametri come ingressi
# separati
# dichiarazioni variabili locali
# {
local in_arg=$1
local i=""
local start=""
local end=""
local num_char=""
local char=""
local argument=""
# }
# conto quanti sono i caratteri
num_char=$(echo $in_arg | wc -m)
let "char -= 1"
# inizializzo le variabili
i=1
start=1
end=1
# inizio la scansione dell'ingresso
while [ "$i" -le "$num_char" ]; do
char=$(echo $in_arg | cut -c$i)
if [ "$char" == ":" ]; then
let "end = i - 1"
argument=$(echo $in_arg | cut -c$start-$end)
let "start = end + 2"
echo $argument
fi
let "i += 1"
done
# restituisco l'ultimo output
let "start = end + 2"
argument=$(echo $in_arg | cut -c$start-)
echo $argument
}
# =======================================================================================
# fine dichiarazione delle funzioni
# =======================================================================================
# =======================================================================================
# inizio programma principale
# =======================================================================================
# inizializzo le variabili
i_start=-1 # contatore per la funzione createindex
i_step=-1 # step per la funzione createindex
file_index=1 # contatore per la funzione filelist
testing=0 # test
# flag
# {
alldowncase_flag=0
alluppercase_flag=0
firstuppercase_flag=0
allfirstupc_flag=0
insertatpos_flag=0
cutatpos_flag=0
prepend_flag=0
append_flag=0
substitute_flag=0
filelist_flag=0
index_flag=0
# }
# prelevo gli argomenti passatimi
while getopts "hctdUuAi:C:p:a:s:f:I:" opt; do
case $opt in
h) dohelp;;
c) doconf;;
t) testing=1;;
d) alldowncase_flag=1;;
U) alluppercase_flag=1;;
u) firstuppercase_flag=1;;
A) allfirstupc_flag=1;;
i) insertatpos_flag=1
insertatpos_val=$OPTARG;;
C) cutatpos_flag=1
cutatpos_val=$OPTARG;;
p) prepend_flag=1
prepend_val=$OPTARG;;
a) append_flag=1
append_val=$OPTARG;;
s) substitute_flag=1
substitute_val=$OPTARG;;
f) filelist_flag=1
filelist_val=$OPTARG;;
I) index_flag=1
index_val=$OPTARG;;
*) echo "======================================================================================="
echo "Spiacente, ma la funzione \"$funzione\" non esiste."
echo "Prova a digitare \"$(basename $0) -h\" per ottenere aiuto."
echo "=======================================================================================";;
esac
done
# memorizzati gli argomenti, elimino quello che non mi serve
shift $(( OPTIND - 1 ))
# prendo i percorsi iniziale e finale
start_path=$1
end_path=$2
# elimino anche questi parametri
shift 2
# ed infine prelevo le opzioni da passare a find
find_opt=$*
# controllo la validità dei parametri
if [ -z "$start_path" -o -z "$end_path" ]; then
echo "Spiacente, ma devi specificare il percorso inziale e finale!"
exit 1
elif [ ! -e $start_path ]; then
echo "Spiacente, ma il file \"$start_path\" non esiste!"
exit 1
elif [ ! -e $end_path ]; then
echo "Spiacente, ma il file \"$end_path\" non esiste!"
exit 1
fi
IFS='
'
# effettuo la rinomina dei file
for new_file in `find $start_path/ $find_opt -mindepth 1 -printf "%f\n" | sort -n`; do
# memorizzo il nome originale
old_file=$(basename $new_file)
new_file=$(basename $new_file)
# effettuo le azioni richieste
if [ "$alldowncase_flag" -eq 1 ]; then
new_file=$(alldowncase "$new_file")
elif [ "$firstuppercase_flag" -eq 1 ]; then
new_file=$(firstuppercase "$new_file")
elif [ "$allfirstuppercase_flag" -eq 1 ]; then
new_file=$(allfirstupc "$new_file")
elif [ "$alluppercase_flag" -eq 1 ]; then
new_file=$(alluppercase "$new_file")
fi
if [ "$insertatpos_flag" -eq 1 ]; then
new_file=$(insertatpos "$new_file" $(extargs $insertatpos_val))
fi
if [ "$cutatpos_flag" -eq 1 ]; then
new_file=$(cutatpos "$new_file" $(extargs $cutatpos_val))
fi
if [ "$prepend_flag" -eq 1 ]; then
new_file=$(prepend "$new_file" $prepend_val)
fi
if [ "$append_flag" -eq 1 ]; then
new_file=$(append "$new_file" $append_val)
fi
if [ "$substitute_flag" -eq 1 ]; then
new_file=$(substitute "$new_file" $(extargs $substitute_val))
fi
if [ "$filelist_flag" -eq 1 ]; then
new_file=$(filelist $filelist_val)
fi
if [ "$index_flag" -eq 1 ]; then
new_file=$(createindex "$new_file" $(extargs $index_val))
fi
if [ ! -e $end_path/$new_file -a "$testing" -eq 0 ]; then
mv $start_path/$old_file $end_path/$new_file
echo "Il file \"$start_path/$old_file\""
echo "è stato rinominato in \"$end_path/$new_file\""
echo ""
elif [ ! -e $end_path/$new_file -a "$testing" -eq 1 ]; then
echo "Il file \"$start_path/$old_file\""
echo "sarà rinominato in \"$end_path/$new_file\""
echo ""
else
echo "Il file \"$end_path/$new_file\""
echo "esiste già, quindi non sarà spostato"
echo ""
fi
# aggiorno i contatori
let "file_index += 1"
# let "i_start += i_step"
done
exit 0
# =======================================================================================
# fine programma principale
# =======================================================================================
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 13:04
da targzeta
Scusa, per essere più rapidi, mi daresti un esempio d'uso? Uso che fallisca ovviamente.
Spina
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 13:11
da tiferet
./bmv -t -I start:3 (directory con qualche file) (stessa directory)
-t -> test, non fa nulla, stampa solo i nuovi nomi
-I start:3 -> inserisce un indice di tre cifre all'inizio del nome del file
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 13:35
da targzeta
Il problema è che esegui la funzione in un altro ambiente, e quindi le variabili sono copiate nel nuovo ambiente. Sto cercando di risolvere, dammi un momento.
Spina
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 13:46
da targzeta
Per farti capire meglio:
se invece di:
Codice: Seleziona tutto
if [ "$index_flag" -eq 1 ]; then
new_file=$(createindex "$new_file" $(extargs $index_val))
fi
ci metti:
Codice: Seleziona tutto
if [ "$index_flag" -eq 1 ]; then
new_file=$(createindex "$new_file" $(extargs $index_val))
createindex "$new_file" $(extargs $index_val) > /dev/null;
fi
allora funziona, perchè invocando la funzione direttamente le variabili vengono modificate, quando invochi la funzione con '$()' allora questa viene eseguita in un nuovo ambiente, e non midifica le variabili dell'ambiente attuale.
Ora vado a mangiare,
vedi se puoi risolvere in maniera migliore, con un buco in pancia non riesco a pensare più di tanto

.
Spina
P.S. Ho anche un altro errore perchè la variabile
non è inizializzata, in effetti la usi solo qui:
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 13:53
da tiferet
Ti ringrazio moltissimo!
Avevo avuto un sospetto del genere notando i "+" accanto ad ogni istruzione nella modalità di debug, ma non sarei mai arrivato da solo a questa conclusione.
Beh, vedrò di trovare una soluzione migliore, ma anche quella che suggerisci tu non è male. Per l'altro errore, grazie per la segnalazione, l'avevo già notato!
A dopo e buon pranzo!
Re: batch - bash renamer
Inviato: ven 13 giu 2008, 14:13
da Mario Vanoni
Uso da tanti anni
http://www.nongnu.org/renameutils/
magari ci trovi qualche spunto utile.