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

Codice: Seleziona tutto

allfirstuppercase_flag
non è inizializzata, in effetti la usi solo qui:

Codice: Seleziona tutto

 elif [ "$allfirstuppercase_flag" -eq 1 ]; then

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.