Rendere uno script ricorsivo

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
fortea
Linux 0.x
Linux 0.x
Messaggi: 24
Iscritto il: gio 15 lug 2010, 14:00
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: fluxbox

Rendere uno script ricorsivo

Messaggio da fortea »

Buon giorno a tutti. Sono nuovo del forum e piuttosto nuovo di Linux.

Mi chiedevo come si può rendere uno script (scritto da me) ricursivo nelle sottodierctory. Nel particolare, il mio comando sostituisce alcuni caratteri (ad esempio gli spazi) nei nomi dei file e delle directory presenti nella directory in cui ci si trova. Vorrei però che all'occorrenza funzionasse anche nei file e nelle directory presenti nelle sottodirectory.
Un'altra cosa: e per farlo funzionare in una directory o su un file espresso come argomento del comando?

Grazie per le risposte, copio il codice:

Codice: Seleziona tutto

#!/bin/sh
#controllo dei parametri passati dalla riga di comando
if [$1 = ]
	then
	echo -n 'Would you like to cancel spaces in all files of this directory? [y/n] '
	read answer_a
	str1="$answer_a"
	if [ $str1 = "y" ]
	then
		REPLACE_CHAR="\ "
	#eliminazione dei file i cui nomi contengono spazi
		for file in ls * 
		do
			if [ "$file" = "ls" ]
			then
				str1="$file" #operazione inutile, non so dirgli di non fare nulla; qui non deve fare niente
			else
			str2=`echo $file | sed s/\ /_/g`  #il comando sed sostituisce nella stringa s il terzo parametro al posto del secondo
			if [ "$file" = $str2 ]
			then
			niente=$file
			#echo $file	#stampa i nomi dei files non modificati		
			else
			echo $file  ">>>>>>" $str2	#stampa i nomi dei files modificandi e modificati		
			mv "$file" $str2 #cambia il nome del file con quello contenuto in $str
			fi
			fi
		done

		REPLACE_CHAR="_-_"
	#eliminazione dei file i cui nomi contengono spazi
		for file in ls * 
		do
			if [ "$file" = "ls" ]
			then
				str3="$file" #operazione inutile, non so dirgli di non fare nulla; qui non deve fare niente
			else
			str4=`echo $file | sed s/_-_/_/g`  #il comando sed sostituisce nella stringa s il terzo parametro al posto del secondo
			if [ "$file" = $str4 ]
			then
			niente=$file	#operazione inutile, ma qui non deve fare niente	
			else
			echo $file  "   >>>>>>   " $str4	#stampa i nomi dei files modificandi e modificati		
			mv "$file" $str4 #cambia il nome del file con quello contenuto in $str
			fi
			fi
		done





	exit
	

	fi
	exit
fi
exit

Avatar utente
masalapianta
Iper Master
Iper Master
Messaggi: 2775
Iscritto il: lun 25 lug 2005, 0:00
Nome Cognome: famoso porco
Kernel: uname -r
Desktop: awesome
Distribuzione: Debian
Località: Roma
Contatta:

Re: Rendere uno script ricursivo

Messaggio da masalapianta »

sotituisci "ls *" (perchè metti "ls"? basta "*") con un find; btw fai prima così:
export OLDIFS=$IFS; export IFS=$'\n';for i in `find . -type f`; do mv "$i" "`echo $i|tr \" \" \"_\"`";done;IFS=$OLDIFS
ovviamente se vuoi rinominare anche le directory basta levare il -type f

Avatar utente
anycolouryoulike
Packager
Packager
Messaggi: 1158
Iscritto il: ven 10 ago 2007, 0:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: Rendere uno script ricursivo

Messaggio da anycolouryoulike »

Io farei così:

Codice: Seleziona tutto

IFS=$'\n'
for i in $(find . -type f -name "* *")
do
mv $i $(echo $i | tr ' ' '_')
done
Sono stato anticipato :)

Avatar utente
conraid
Staff
Staff
Messaggi: 13630
Iscritto il: gio 14 lug 2005, 0:00
Nome Cognome: Corrado Franco
Slackware: current64
Desktop: kde
Località: Livorno
Contatta:

Re: Rendere uno script ricursivo

Messaggio da conraid »

anycolouryoulike ha scritto:Io farei così:

Codice: Seleziona tutto

IFS=$'\n'
for i in $(find . -type f -name "* *")
do
mv $i $(echo $i | tr ' ' '_')
done
Sono stato anticipato :)
io quoterei $1 però

Avatar utente
anycolouryoulike
Packager
Packager
Messaggi: 1158
Iscritto il: ven 10 ago 2007, 0:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: Rendere uno script ricursivo

Messaggio da anycolouryoulike »

conraid ha scritto:
anycolouryoulike ha scritto:Io farei così:

Codice: Seleziona tutto

IFS=$'\n'
for i in $(find . -type f -name "* *")
do
mv $i $(echo $i | tr ' ' '_')
done
Sono stato anticipato :)
io quoterei $1 però
Non ce n'è bisogno modificando l'IFS.

fortea
Linux 0.x
Linux 0.x
Messaggi: 24
Iscritto il: gio 15 lug 2010, 14:00
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: fluxbox

Re: Rendere uno script ricursivo

Messaggio da fortea »

dunque dunque... innanzitutto grazie per l'attenzione. vi ho detto, sono piuttosto ignorante in materia.
In questo modo lo script è ricursivo perchè si utilizza find, giusto? e se ora non lo volessi più ricursivo si potrebbe mantenere una struttura analoga?

Comunque in questo modo mi da sempre questo errore:

Codice: Seleziona tutto

mv: cannot move `./ciao ciao/del sp 1' to `./ciao_ciao/del_sp_1': No such file or directory
Inoltre modifica anche file e directory nascosti, che sarebbe meglio non modificare perchè potrebbe appartenere a qualche programma.

Avatar utente
anycolouryoulike
Packager
Packager
Messaggi: 1158
Iscritto il: ven 10 ago 2007, 0:00
Slackware: 12.2
Kernel: 2.6.34.8
Desktop: KDE 3.5.10

Re: Rendere uno script ricursivo

Messaggio da anycolouryoulike »

Come è già stato detto, per rinominare anche le directory basta togliere -type f.
Se vuoi escludere i file e le directory nascosti puoi filtrare i risultati ad esempio così:

Codice: Seleziona tutto

find | sed '/\/\./d'

Avatar utente
conraid
Staff
Staff
Messaggi: 13630
Iscritto il: gio 14 lug 2005, 0:00
Nome Cognome: Corrado Franco
Slackware: current64
Desktop: kde
Località: Livorno
Contatta:

Re: Rendere uno script ricursivo

Messaggio da conraid »

anycolouryoulike ha scritto:
conraid ha scritto:
anycolouryoulike ha scritto:Io farei così:

Codice: Seleziona tutto

IFS=$'\n'
for i in $(find . -type f -name "* *")
do
mv $i $(echo $i | tr ' ' '_')
done
Sono stato anticipato :)
io quoterei $1 però
Non ce n'è bisogno modificando l'IFS.
questa mi mancava :oops:

fortea
Linux 0.x
Linux 0.x
Messaggi: 24
Iscritto il: gio 15 lug 2010, 14:00
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: fluxbox

Re: Rendere uno script ricorsivo

Messaggio da fortea »

Ma l'opzione -name a cosa serve? Non riesco a capire perchè se la metto non trova le sottodirectory, mentre se non la metto trova tutti i file presenti in tutte le sottodirectory, indistantamente dal fatto che contengano la stringa cercata o meno...
Comunque ho risolto il problema utilizzando l'opzione -regex e mettendo un '.' davanti ai caratteri jolly.
Ora il problema è un altro.

Una volta trovati i file e le directory cercati, lo script comincia a modificarne il nome; per testarlo ho creato le seguenti directory nella mia home.
|-- ciao cao1
| |-- cia ciAO2
| | `-- pro prova2.txt
| `-- prov prov1.txt
Il comando mv modifica per primo il nome di "./ciao\ cao1", non riuscendo così a modificare gli altri perchè l'argomento passatogli contiene ancora il nome non modificato.

Soluzioni? L'unica che mi viene in mente è applicare più volte il find, quante volte è stato inserito dall'utente, ma è un po' spigolosa...

Grazie mille, allego il codice allo stato attuale e il messaggio d'errore:

Codice: Seleziona tutto

IFS=$'\n'
		for i in $(find $str1 -regex .*\ .* | sed '/\/\./d' )
		do
			mv -v $i $(echo $i | tr '\ ' '_')
		done

Codice: Seleziona tutto

`./ciao cao1' -> `./ciao_cao1'
mv: cannot stat `./ciao cao1/cia ciAO2': No such file or directory
mv: cannot stat `./ciao cao1/cia ciAO2/pro prova2.txt': No such file or directory
mv: cannot stat `./ciao cao1/prov prov1.txt': No such file or directory

albatrosla
Packager
Packager
Messaggi: 1339
Iscritto il: sab 27 mar 2004, 0:00
Slackware: current
Desktop: fluxbox.git
Località: Collegno, but made in Friûl
Contatta:

Re: Rendere uno script ricorsivo

Messaggio da albatrosla »

Secondo me, fai uno script che esegue la singola operazione da fare su ciascun file, ad es.:

Codice: Seleziona tutto

#!/bin/bash
# Crea una directory tmp e copia in essa il file, argomento dello script
mkdir -p tmp
cp "$@" ./tmp
quindi lo rendi eseguibile e poi ti appoggi solo su find:

Codice: Seleziona tutto

find . -name "<pattern>" -exec script.sh {} \;
Bisogna fare attenzione alle virgolette su $@ per evitare che l'argomento passato da find allo script, qualora abbia degli spazi o altri caratteri che necessitano escaping, mandi tutto a rotoli.

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6629
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Rendere uno script ricorsivo

Messaggio da targzeta »

Impara a leggere i manuali, non è che per ogni problemino relativo alle opzioni di find devi fare una domanda!!!
Comunque, vedi se ti può essere utile questo:

Codice: Seleziona tutto

$> mkdir -p casa/ciao\ cao1/cia\ ciAO2; touch casa/ciao\ cao1/cia\ ciAO2/pro\ prova2.txt; touch casa/ciao\ cao1/pro\ prova\ 2.txt

$> tree casa
casa/
`-- ciao cao1
    |-- cia ciAO2
    |   `-- pro prova2.txt
    `-- pro prova 2.txt

$> (IFS=$'\n'; for file in $(find casa/ -depth -name "* *"); do dir=$(dirname $file); name=$(basename $file); mv $file ${dir}/${name// /_}; done)

$> tree casa
casa/
`-- ciao_cao1
    |-- cia_ciAO2
    |   `-- pro_prova2.txt
    `-- pro_prova_2.txt
Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

fortea
Linux 0.x
Linux 0.x
Messaggi: 24
Iscritto il: gio 15 lug 2010, 14:00
Slackware: 13.0
Kernel: 2.6.29.6
Desktop: fluxbox

Re: Rendere uno script ricorsivo

Messaggio da fortea »

spina ha scritto:Impara a leggere i manuali, non è che per ogni problemino relativo alle opzioni di find devi fare una domanda!!!
Io l'ho letto il manuale, ma non sono molto ferrato con l'inglese e in italiano non l'ho trovato... :(
Per il resto grazie mille ancora, in questo modo funziona benissimo. Ancora una domanda (certamente da ignorante): si può riutilizzare un parametro all'interno dello script passato da riga di comando nel lanciare lo script?

Avatar utente
targzeta
Iper Master
Iper Master
Messaggi: 6629
Iscritto il: gio 3 nov 2005, 14:05
Nome Cognome: Emanuele Tomasi
Slackware: 64-current
Kernel: latest stable
Desktop: IceWM
Località: Carpignano Sal. (LE) <-> Pisa

Re: Rendere uno script ricorsivo

Messaggio da targzeta »

I parametri sono acceduti tramite $i dove i è il numero del parametro che ti serve. Cerca il manuale della bash. Ad esempio se hai uno script chiamato 'casa.sh' e lo lanci con: casa.sh ciao. Allora il parametro 'ciao' lo trovi nella variabile $1.

Però ci sono altre questioni, quindi leggiti il man della bash, che esiste, anche se vecchio, in italiano.
Emanuele
Se pensi di essere troppo piccolo per fare la differenza, prova a dormire con una zanzara -- Dalai Lama

Rispondi