Précédent   Forum des professionnels en informatique > Systèmes > Linux > Applications > Shell
Shell Vos questions sur l'utilisation des commandes shell
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
Vieux 25/02/2010, 14h07   #1
Membre à l'essai
 
Inscription : février 2006
Messages : 91
Détails du profil
Informations forums :
Inscription : février 2006
Messages : 91
Points : 23
Points : 23
Par défaut Passer des répertoires et sous répertoire de minuscules en majuscules

Bonjour à tous

J'ai un répertoire contenant de nombreux répertoires, eux-mêmes contenant d'autres nombreux sous-répertoire.
Certains sont en majuscules, d'autres en minuscules, d'autres un peu des 2....
Ce que j'aimerai, c'est renommé tout les répertoires et sous-répertoire du répertoire d'origine en majuscule.
Je me doute que je dois faire une boucle pour rechercher tout les répertoires puis de les renommer après avoir appliquer un tr dessus mais mon souci c'est que je ne dois pas m'y prendre dans le bon sens car après avoir renommé les 1er répertoires, il ne retrouve plus les sous-répertoires de ces répertoires....logique ils ont déjà changé de nom....

Exemple :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
tata@toto:/rep/reptest> find . -type d
.
./TEST2
./TEST2/TEST
./TEST2/TEST/TEst1
./TEST2/TEST/TEst2
./TEST2/TEST1
./TEST2/TEST1/tesT1
./TEST2/TEST1/Test2
./TEST2/TEST2
./test
./test/test1
./test/tesT2
./test/TEST3
./tesT1
./tesT1/test
./tesT1/test2
./tesT1/teSt3
tata@toto:/rep/reptest> 
 
tata@toto:/rep/reptest> ./sar.sh 
mv: `.' et `./.' identifient le même fichier.
mv: ne peut écraser le répertoire `./TEST2/TEST2'
mv: ne peut déplacer `./TEST2/TEST' vers un sous-répertoire de lui-même `./TEST2/TEST/TEST'
mv: ne peut déplacer `./TEST2/TEST1' vers un sous-répertoire de lui-même `./TEST2/TEST1/TEST1'
mv: ne peut déplacer `./TEST2/TEST2' vers un sous-répertoire de lui-même `./TEST2/TEST2/TEST2'
mv: ne peut évaluer `./test/test1': Aucun fichier ou répertoire de ce type
mv: ne peut évaluer `./test/tesT2': Aucun fichier ou répertoire de ce type
mv: ne peut évaluer `./test/TEST3': Aucun fichier ou répertoire de ce type
mv: ne peut évaluer `./tesT1/test': Aucun fichier ou répertoire de ce type
mv: ne peut évaluer `./tesT1/test2': Aucun fichier ou répertoire de ce type
mv: ne peut évaluer `./tesT1/teSt3': Aucun fichier ou répertoire de ce type
tata@toto:/rep/reptest> ll
total 72
drwxr-xr-x   5 tata tata    72 2010-02-25 14:04 .
drwxr-xr-x  10 tata tata    4096 2010-02-25 13:45 ..
-rwxr-xr-x   1 tata tata    93 2010-02-25 13:45 sar.sh
drwxr-xr-x   5 tata tata    42 2010-02-25 13:49 TEST
drwxr-xr-x   5 tata tata    41 2010-02-25 13:48 TEST1
drwxr-xr-x   5 tata tata    41 2010-02-25 13:49 TEST2
tata@toto:/rep/reptest>
Mon code actuel
Code :
1
2
3
4
5
for each in `find . -type d`
do
newname=`echo $each | tr [a-z] [A-Z]`
mv $each $newname
done
Comment je peux m'y prendre ?

Merci de votre aide !
amans est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/02/2010, 15h27   #2
Expert Confirmé
 
Avatar de N_BaH
 
Inscription : février 2008
Messages : 1 897
Détails du profil
Informations forums :
Inscription : février 2008
Messages : 1 897
Points : 3 677
Points : 3 677
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#/bin/bash
 
reName() {
   for each in "$1"/*
   do [ -d "$each" ] && {
         dir="$each"
         new=$(ChangeCase "$dir")
         path="${dir%/*}"
         echo -e "\e[00;32m$dir\e[00m -> \e[00;36m$path/$new\e[00m"
         mv "$dir" "$path/$new"
         reName "$path/$new"
      }
   done
}
 
getopts ul option
case $option in
   u) ChangeCase() { tr [a-z] [A-Z] <<<"${1##*/}"; }
   ;;
   l) ChangeCase() { tr [A-Z] [a-z] <<<"${1##*/}"; }
   ;;
   *) echo "il faut indiquer une option\n\t-u mettre en majuscule\n\t-l mettre en minuscule"
      exit
   ;;
esac
shift #$(($OPTIND - 1))
reName "${1:-.}"

Dernière modification par N_BaH ; 28/02/2010 à 17h58.
N_BaH est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/02/2010, 15h50   #3
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
Une solution:
Code :
1
2
3
4
5
6
7
#!/bin/bash
 
for dir in $(find ${1:-.} -type d | awk -F '/' '{print NF, $0}' | sort -nr -k 1,1 | awk '{print $2}')
do
  newDir=$(echo $dir | awk 'BEGIN {FS=OFS="/"} {$NF=toupper($NF); print}')
  [[ $newDir != $dir ]] && mv $dir $newDir
done
Si on passe un argument au script, c'est le répertoire à partir duquel il faut faire les modifications. Si pas d'argument, c'est le répertoire courant.
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/02/2010, 16h01   #4
Membre Expert
 
Homme
budget et contrôle de gestion
Inscription : décembre 2006
Messages : 865
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 44
Localisation : France

Informations professionnelles :
Activité : budget et contrôle de gestion
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : décembre 2006
Messages : 865
Points : 1 320
Points : 1 320
Salut,

Je vais encore mettre mon grain de sel dans vos jolies boucles de programmes.

Mais la commande rename permet cela (à intégrer dans une boucle bien sûr).

Code :
rename "y/[A-Z]/[a-z]/" <ce_que_tu_veux_renommer>
@jmelyn et N_BaH : pourquoi faire simple quand on peut faire compliquer hein
__________________
Winnt

C'est en Linuxant qu'on devient .... geek

Intel Core i5 750 / 8 Go ram / Hdd 2 To / NVIDIA GeForce GTS 250 1Go sous Gentoo.
Dual core E6300 / 2Go ram / Hdd 1 To / Ati 9800XT sous Debian Testing.
Atom N330 / 4Go ram / Hdd 5To / intel GMA 950 sous Debian Testing
Winnt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 25/02/2010, 16h16   #5
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
As-tu essayé, winnt?

Exemple:
dir1/dir2/dir3 --> dir1/dir2/DIR3

On ne change qu'un seul nom de répertoire à la fois dans les sous-répertoires sinon...
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/02/2010, 17h35   #6
Membre Expert
 
Homme
budget et contrôle de gestion
Inscription : décembre 2006
Messages : 865
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 44
Localisation : France

Informations professionnelles :
Activité : budget et contrôle de gestion
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : décembre 2006
Messages : 865
Points : 1 320
Points : 1 320
Salut,

Le problème de amans m'ayant intéressé je me suis penché dessus à faire un petit script (largement perfectible) afin de récupérer la liste des répertoires (et ceci sans awk ).

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/bash
#
# le programme prend en paramêtre un répertoire
#
# But du script : lister récursivement les répertoires à partir d'un répertoire donné en paramêtre
#
cyan="\e[1;36m"
blanc="\e[1;37m"
function liste_repertoire
{
#local repertoire
for i in $(ls -1F $1 | grep ".*/$")
do
repertoire=$1"$i"
	if [[ -d $repertoire ]]
		then
			echo -e $cyan"Répertoire : "$blanc"$repertoire"
			cd $repertoire
			liste_repertoire $repertoire
	else
		echo -e $cyan"Répertoire : "$blanc"$repertoire"
	fi
done
 
}
 
 
if [[ -d $1 ]]
	then
		liste_repertoire $1"/"
elif [[ -z $1 ]]
	then
		echo "Aucun répertoire saisi."
		echo "Fin du programme"
		exit
else
	echo $1" n'est pas un répertoire."
	echo "Fin du programme."
	exit
fi
Il manque pas mal de choses pour qu'il soit fini mais....
__________________
Winnt

C'est en Linuxant qu'on devient .... geek

Intel Core i5 750 / 8 Go ram / Hdd 2 To / NVIDIA GeForce GTS 250 1Go sous Gentoo.
Dual core E6300 / 2Go ram / Hdd 1 To / Ati 9800XT sous Debian Testing.
Atom N330 / 4Go ram / Hdd 5To / intel GMA 950 sous Debian Testing
Winnt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/02/2010, 22h03   #7
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
Winnt, en gros tu voudrais faire ce que fait la commande
Mais sans utiliser find, Okay? Alors regarde:
Code :
1
2
3
4
5
6
7
#!/bin/bash
 
[[ -d $1 ]] && echo $1 || exit
for dir in $(ls -A1pr "$1" 2> /dev/null | grep "/$")
do
  $0 "$1/${dir%/}"
done
Le résultat est le même que find (et dans le même ordre), sauf que le programme ne sort aucun message d'erreur si l'argument passé au script n'est pas valide (répertoire inexistant).
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 28/02/2010, 22h09   #8
Membre Expert
 
Homme
budget et contrôle de gestion
Inscription : décembre 2006
Messages : 865
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 44
Localisation : France

Informations professionnelles :
Activité : budget et contrôle de gestion
Secteur : Administration - Collectivité locale

Informations forums :
Inscription : décembre 2006
Messages : 865
Points : 1 320
Points : 1 320
Salut,

Merci pour ce bout de code jmelyn.
Je m'en vais le décortiquer de ce pas. Et parfaire ma culture
__________________
Winnt

C'est en Linuxant qu'on devient .... geek

Intel Core i5 750 / 8 Go ram / Hdd 2 To / NVIDIA GeForce GTS 250 1Go sous Gentoo.
Dual core E6300 / 2Go ram / Hdd 1 To / Ati 9800XT sous Debian Testing.
Atom N330 / 4Go ram / Hdd 5To / intel GMA 950 sous Debian Testing
Winnt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 10h45   #9
Membre à l'essai
 
Inscription : février 2006
Messages : 91
Détails du profil
Informations forums :
Inscription : février 2006
Messages : 91
Points : 23
Points : 23
Merci à tous pour votre aide !
Désolé de ne pas avoir répondu plus tôt...

En fait j'ai trouvé comment faire même si c'est relativement bourrin...

Code :
1
2
3
4
5
6
7
8
9
10
for each in `find $1 -type d | sort -r`
do
 
name=`echo ${each##*/}`
path=`echo ${each%%$name*}`
newname=`echo $name | tr [a-z] [A-Z]`
newname=$path$newname
 
mv $each $newname
done
amans est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 10h52   #10
Modérateur
 
Avatar de pitipoisson
 
Homme Yves Reecht
Chercheur
Inscription : septembre 2006
Messages : 1 920
Détails du profil
Informations personnelles :
Nom : Homme Yves Reecht
Âge : 32
Localisation : France, Finistère (Bretagne)

Informations professionnelles :
Activité : Chercheur
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : septembre 2006
Messages : 1 920
Points : 3 060
Points : 3 060
Bonjour à tous,

Pourquoi s'embêter à faire des boucles puisque la commande find peu s'en charger ?
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ find . -type d
.
./TEST2
./TEST2/TEST1
./TEST2/TEST1/Test2
./TEST2/TEST1/tesT1
./TEST2/TEST
./TEST2/TEST/TEst2
./TEST2/TEST/TEst1
./test
./test/test1
./test/TEST3
./test/tesT2
$ find . -depth -type d -execdir rename "y/[a-z]/[A-Z]/" '{}' \;
$ find . -type d
.
./TEST2
./TEST2/TEST1
./TEST2/TEST1/TEST2
./TEST2/TEST1/TEST1
./TEST2/TEST
./TEST2/TEST/TEST2
./TEST2/TEST/TEST1
./TEST
./TEST/TEST2
./TEST/TEST3
./TEST/TEST1
L'option -depth est nécessaire pour que les sous-dossiers soient traités en premier. Comme find semble chercher tous les dossiers avant l'exécution de commande, on risque - sans cette option - de se trouver dans le cas d'un chemin qui n'existe plus au moment de l'exécution du rename.
__________________
Forum LaTeX : pour des réponses rapides et appropriées, pensez à poster un
ECM = Exemple (reproduit le problème) Complet (document compilable) Minimal (ne postez pas votre thèse !)

Une solution vous convient ? N'oubliez pas le tag


)><))))°>
pitipoisson est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 11h18   #11
Membre à l'essai
 
Inscription : février 2006
Messages : 91
Détails du profil
Informations forums :
Inscription : février 2006
Messages : 91
Points : 23
Points : 23
dans mon find je n'ai pas l'option execdir... seulement exec
y-a-t'il une différence ?
parceque juste avec exec, il ne se passe rien :/
je connais pas bien la commande rename en même temps, ça vient peut-être de là
amans est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 11h35   #12
Modérateur
 
Avatar de pitipoisson
 
Homme Yves Reecht
Chercheur
Inscription : septembre 2006
Messages : 1 920
Détails du profil
Informations personnelles :
Nom : Homme Yves Reecht
Âge : 32
Localisation : France, Finistère (Bretagne)

Informations professionnelles :
Activité : Chercheur
Secteur : Agroalimentaire - Agriculture

Informations forums :
Inscription : septembre 2006
Messages : 1 920
Points : 3 060
Points : 3 060
Citation:
Envoyé par amans Voir le message
y-a-t'il une différence ?
-execdir exécute la commande suivante à partir du sous-répertoire contenant le fichier trouvé et non du dossier racine (e.g. l'argument '{}' représente ./Test2 [commande exécutée dans ./TEST2/TEST1/] au lieu de ./TEST2/TEST1/Test2 [commande exécutée dans ./]).

Tu n'as pas l'action (voir man find) ou bien find refuse l'exécution ?
Ce dernier cas pourrait être du à des chemins relatifs dans ton $PATH.
__________________
Forum LaTeX : pour des réponses rapides et appropriées, pensez à poster un
ECM = Exemple (reproduit le problème) Complet (document compilable) Minimal (ne postez pas votre thèse !)

Une solution vous convient ? N'oubliez pas le tag


)><))))°>
pitipoisson est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 12h09   #13
Membre à l'essai
 
Inscription : février 2006
Messages : 91
Détails du profil
Informations forums :
Inscription : février 2006
Messages : 91
Points : 23
Points : 23
je ne l'ai pas du tout dans le man...
mais en tout cas c'est bon à savoir, le jour où je tombe sur une autre version de find
amans est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 14h24   #14
Expert Confirmé
 
Avatar de N_BaH
 
Inscription : février 2008
Messages : 1 897
Détails du profil
Informations forums :
Inscription : février 2008
Messages : 1 897
Points : 3 677
Points : 3 677
Contrairement à ce que j'aurais pensé, sur 122 répertoires, find met plus de temps à effectuer ce traitement :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
time find ...
 
real	0m7.213s
user	0m6.032s
sys	0m0.884s
 
 
time monScript -u .
 
real	0m1.478s
user	0m0.468s
sys	0m0.924s

Dernière modification par N_BaH ; 01/03/2010 à 15h27.
N_BaH est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 15h27   #15
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
Pour les temps d'exécution, find devrait normalement être plus rapide. Mais il y a aussi le temps de la commande et l'option -execdir doit surement faire un cd à chaque fois, ce qui est assez long.

C'est lequel ton script? As-tu mesuré celui que j'ai posté, ainsi que celui d'Amans? En optimisant ce dernier un peu, on obtient:
Code :
1
2
3
4
for dir in $(find $1 -type d 2> /dev/null | sort -r)
do
  [[ $dir != "." ]] && mv $dir ${dir%/*}/$(echo ${dir##*/} | tr [a-z] [A-Z])
done
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 15h33   #16
Expert Confirmé
 
Avatar de N_BaH
 
Inscription : février 2008
Messages : 1 897
Détails du profil
Informations forums :
Inscription : février 2008
Messages : 1 897
Points : 3 677
Points : 3 677
sur ce dernier (bien plus court), on est à peu près égal :
real 0m1.177s
user 0m0.312s
sys 0m0.800s

monScript est ici
N_BaH est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 15h38   #17
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
As-tu Bash version 4 (bash --version)? Le cas échéant, peux-tu tester ceci:
Code :
1
2
3
4
5
for dir in $(find $1 -type d 2> /dev/null | sort -r)
do
  newDir=${dir##*/}
  [[ $dir != "." ]] && mv $dir ${dir%/*}/${newDir^^}
done
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 16h11   #18
Expert Confirmé
 
Avatar de N_BaH
 
Inscription : février 2008
Messages : 1 897
Détails du profil
Informations forums :
Inscription : février 2008
Messages : 1 897
Points : 3 677
Points : 3 677
j'ai bash4 sur une Squeeze en VServer, dont je ne me sers pas assez

résultat :
real 0m0.516s
user 0m0.176s
sys 0m0.264s

fiou!!! la vache !
N_BaH est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 16h39   #19
Membre chevronné
 
Inscription : septembre 2007
Messages : 685
Détails du profil
Informations personnelles :
Âge : 48
Localisation : Suisse

Informations forums :
Inscription : septembre 2007
Messages : 685
Points : 723
Points : 723
Attends, c'est la même machine et les mêmes répertoires à modifier, n'est-ce pas? C'est la raison pour laquelle je t'ai demandé d'essayer.

Pour encore optimiser, je ferais bien encore cela:
Code :
1
2
3
4
5
6
for path in $(find "${1:-.}" -type d 2> /dev/null | sort -r)
do
  leaf="${path##*/}"
  newPath="${path%/*}/${leaf^^}"
  [[ "$path" != "$newPath" ]] && mv "$path" "$newPath"
done
Je corrige une erreur en même temps parce que si le répertoire est déjà en majuscule, faut pas essayer de changer quoi que ce soit (sinon erreur!). Je sécurise aussi pour éviter les problèmes avec les noms de répertoires comportant des espaces.

L'accélération est due au traitement qui ne sort pas du shell pour changer la casse du nom.
__________________
Un problème bien posé est déjà résolu (H. Bergson).
jmelyn est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/03/2010, 17h17   #20
Expert Confirmé
 
Avatar de N_BaH
 
Inscription : février 2008
Messages : 1 897
Détails du profil
Informations forums :
Inscription : février 2008
Messages : 1 897
Points : 3 677
Points : 3 677
Citation:
Envoyé par jmelyn
Attends, c'est la même machine et les mêmes répertoires à modifier, n'est-ce pas?
et oui, et non : physiquement oui, mais le nombre de taches (selon top) sur l'hôte (bash 4.1.0) et l'invité (bash 3.2.39) n'est pas le même (hôte : 112; invité : 7).
Et toujours 120 répertoires.

un petit oubli :
Code :
[[ "$leaf" != "." && "$path" != "$newPath" ]] && mv "$path" "$newPath"

Dernière modification par N_BaH ; 01/03/2010 à 17h29.
N_BaH est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +1. Il est actuellement 07h40.


 
 
 
 
Partenaires

Hébergement Web