#1 Le 21/06/2008, à 20:18
- spohyak
Finalisation d'un pti script pour renommer en série des répertoires
Bonjour,
Jme suis mis au bash depuis quelques jours, mais j'ai un peu de mal à finaliser le script ci-dessous :
#!/bin/sh
for i in /home/james/*
do
#ne garder que le nom du répertoire
dirname="$(basename $i)"
#etape 1
echo="***traitement de $dirname"
#suppression des caractères/chaînes indésirables
dirnamefinal="$(echo $dirname | \
sed -e 's/-[^-]*$//' | \
sed -e 's#\(.ANE\)##gi' | \
sed -e 's#\.# #g')"
#prise en compte de l'espace
final="$(echo $dirnamefinal | \
sed -e 's# #\ #g')"
#renommage effectif
mv $i $final
echo "-->résultat : $dirnamefinal"
done
Lorsque je le lance sur un repertoire de test /home/james/Toto.Est.Mignon.Mais.C.Est.Un.Petit.Ane-2008 j'obtiens ce message d'erreur :
# ./rename.dir.sh
mv: la cible `Petit' n'est pas un répertoire
-->résultat : Toto Est Mignon Mais C Est Un Petit
Le résultat echoé est bien correct à mes attentes, mais le mv ne marche pas ...
J'ai rajouté la partie #prise en compte de l'espace mais ca ne sert à rien, j'ai aussi essayé différentes solutions avec le mv :
mv "$i" "$final"
mv /home/james/$i /home/james/$final
mv "/home/james/$i" "/home/james/$final"
et toutes les combinaisons possibles mais rien n'y fait
Si quelqu'un a une petite idée ...
Merci
Hors ligne
#2 Le 21/06/2008, à 20:57
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
Sans avoir tester, essaie ceci :
final="$(echo $dirnamefinal | \
sed -e 's# #\\ #g')"
-- Lucid Lynx --
Hors ligne
#3 Le 21/06/2008, à 21:15
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Merci pour ton test mais ca fait pareil
J'ai enlevé cette partie et j'ai testé avec
mv $i "/home/james/$dirnamefinal" et ça roule
En revanche ca bug si ya deja des dirs avec des espaces
Hors ligne
#4 Le 21/06/2008, à 21:45
- Alain.g
Re : Finalisation d'un pti script pour renommer en série des répertoires
Salut
Normal que ça pose problème, tu n'utilises pas les guillements là où il faut vraiment (variables)
Il faut faire mv "$i" et non mv $i
de même : dirname=$(basename "$i") et non dirname="$(basename $i)"
et encore dirnamefinal=$(echo "$dirname" | .. et non pas dirnamefinal="$(echo $dirname | ..
Par aillleurs, pour un script bash, c'est #!/bin/bash et non #!/bin/sh
pour ne viser que les répertoires : for i in /home/james/*/
avec le slash à la fin/
Concernant sed, plutôt que "sed -e 's///' | sed -e 's///'" , il est possible de faire "sed -e 's///' -e 's///'" ou même "sed -e 's/// ; s///'"
par exemple :
sed 's/-[^-]*$// ; s#\(.ANE\)##gi ; s#\.# #g'
Au passage, tu utilises des parenthèses de mémorisation, mais sans références arrières, il doit s'agir d'une erreur
Xubuntu Karmic !
Hors ligne
#5 Le 22/06/2008, à 10:15
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Oke impeccable merci à vous deux.
Concernant sed, plutôt que "sed -e 's///' | sed -e 's///'" , il est possible de faire "sed -e 's///' -e 's///'" ou même "sed -e 's/// ; s///'"
par exemple :sed 's/-[^-]*$// ; s#\(.ANE\)##gi ; s#\.# #g'
Vi mais je préfère pour plus de lisibilité avoir un sed par ligne. Pour un début jtrouve ca plus clair
Au passage, tu utilises des parenthèses de mémorisation, mais sans références arrières, il doit s'agir d'une erreur
Tu parles de la partie avec le .ANE ? oui pasqu'en fait c'est s#\(TERME1\|TERME2\|...)##gi
Voila
Désormais j'aimerais mettre une condition qui permette de sauter les répertoires qui sont déjà traités (ie qui ont déjà des espaces dans leur nom) mais je ne vois pas trop comment traduire cette condition ...
Dernière modification par spohyak (Le 22/06/2008, à 10:17)
Hors ligne
#6 Le 22/06/2008, à 12:53
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
remplace ton
for i in /home/james/*
par
for i in `find ~ -type d| grep -v "[[:space:]]"`
-- Lucid Lynx --
Hors ligne
#7 Le 22/06/2008, à 21:03
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
remplace ton
for i in /home/james/*
par
for i in `find ~ -type d| grep -v "[[:space:]]"`
Le répertoire d'application c'est ~ donc pour l'appliquer à un rep lambda je tape :
for i in `find /home/james/blabla/ -type d| grep -v "[[:space:]]"`
?
Merci pour la commande sinon !
Dernière modification par spohyak (Le 22/06/2008, à 21:11)
Hors ligne
#8 Le 22/06/2008, à 22:29
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
yep !
-- Lucid Lynx --
Hors ligne
#9 Le 23/06/2008, à 07:13
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Hmmm, lorsque je mets :
for i in `find /home/james/TEST/ -type d| grep -v "[[:space:]]"`
J'obtiens cela :
# ./rename.dir.sh
***traitement de TEST
mv: ne peut déplacer `/home/james/TEST/' vers un sous-répertoire de lui-même `/home/james/TEST/TEST'
-->résultat : TEST
Hors ligne
#10 Le 23/06/2008, à 08:39
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
oups !!!
c'est ma faute, j'ai oublié une négation !
for i in `find /home/james/TEST/ ! -type d| grep -v "[[:space:]]"`
D'ailleurs, je ne sais plus pourquoi j'avais mis une recherche sur les dossiers plutôt que sur les fichiers ! Donc, on obtient :
for i in `find /home/james/TEST/ -type f| grep -v "[[:space:]]"`
Par ailleurs, la commande find effectue par défaut une recherche dans la sous-arborescence. Si tu ne le souhaites pas, ajoute le paramètre -maxdepth 1. Ce qui donne :
for i in `find /home/james/TEST/ -maxdepth 1 -type f| grep -v "[[:space:]]"`
Enfin, la commande find permet aussi de filter avec des expressions régulières (option -regex ou -iregex) mais l'expression régulière doit correspondre au format complet du nom de fichier et c'est moins "lisible" (avec -maxdepth 1) :
for i in `find /home/james/TEST/ -maxdepth 1 -type f -a ! -iregex "^.*[\ ]+.*$"`
Dernière modification par Totor (Le 23/06/2008, à 08:40)
-- Lucid Lynx --
Hors ligne
#11 Le 23/06/2008, à 12:46
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Merci pour toutes ces explications Totor
Tu ne t'étais pas trompé, c'est bien de dossiers qu'il s'agit, j'ai donc laissé le -type d.
En revanche j'ai utilisé la soluce iregex
Le script ignore bien les répertoires déjà traités (donc déjà avec espace), par contre j'ai toujours une erreur :
# ./rename.dir.sh
***traitement de TEST
mv: ne peut déplacer `/home/james/TEST/' vers un sous-répertoire de lui-même `/home/james/TEST/TEST'
-->résultat : TEST
Merci bien !
Dernière modification par spohyak (Le 23/06/2008, à 12:48)
Hors ligne
#12 Le 23/06/2008, à 13:07
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
justement, c'est le - type d qui fait tomber ton script en erreur. En effet, tu fais
dirname="$(basename $i)"
alors que $i est déjà un dossier !
Du coup, tu essaies de déplacer le dossier $i dans un sous dossier de lui même car tu te situes dans le dossier /home/james/TEST/ quand tu lances le script (c'est ce qui t'évite de préciser entièrement le chemin de destination).
Ton script fonctionnait avant car la variable i contenait dans noms de fichiers (et je suppose que tu n'avais pas de sous-dossier)
c'est pour cela que j'ai changé le -type d en -type f !
si tu veux garder le -type d alors, remplace :
dirname="$(basename $i)"
par
dirname="$i"
ça devrait être bon !
EDIT : arf, non !! c'est pas bon car il se peut que tu renommes des dossiers parents
Le plus simple est que tu utilises le -type f
Dernière modification par Totor (Le 23/06/2008, à 13:14)
-- Lucid Lynx --
Hors ligne
#13 Le 23/06/2008, à 13:37
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
justement, c'est le - type d qui fait tomber ton script en erreur. En effet, tu fais
dirname="$(basename $i)"
alors que $i est déjà un dossier !
Oke
Du coup, tu essaies de déplacer le dossier $i dans un sous dossier de lui même car tu te situes dans le dossier /home/james/TEST/ quand tu lances le script (c'est ce qui t'évite de préciser entièrement le chemin de destination).
non justement mon script est dans /home/james/ et je le lance de là
Avec le -f je n'ai plus l'erreur, il est vrai, mais il ne me renomme plus rien pour ceux qui ne sont pas encore traités )
Avec un if ca serait pas plus simple ?
if (ya un repertoire avec un espace alors ne fais rien)
sinon continue la boucle et run le script
Hors ligne
#14 Le 23/06/2008, à 14:08
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
tu peux reposter ton script... je sais plus trop où tu en es
Totor a écrit :Du coup, tu essaies de déplacer le dossier $i dans un sous dossier de lui même car tu te situes dans le dossier /home/james/TEST/ quand tu lances le script (c'est ce qui t'évite de préciser entièrement le chemin de destination).
non justement mon script est dans /home/james/ et je le lance de là
oui oui, c'est ce à quoi je pensais !
Dernière modification par Totor (Le 23/06/2008, à 14:11)
-- Lucid Lynx --
Hors ligne
#15 Le 23/06/2008, à 15:32
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
bon, comme je n'avais pas grand chose à faire au taf (c'est surtout que ça ne m'intéresse pas ), j'ai travaillé sur ton script !
l'un des problème est que find retourne le dossier lui même. donc il sera traité et renommé et c'est pas cool. il faut donc le filtrer (d'où le sed -n '2,$p')
voilà ce que ça donne :
#!/bin/sh
for i in `find /home/james/TEST -maxdepth 1 -type d -a ! -iregex "^.*[\ ]+.*$"|sed -n '2,$p'`
do
#ne garder que le nom du rértoire
dossier="`basename ${i}`"
parent="`dirname ${i}`"
#etape 1
echo="***traitement de ${dossier}"
#suppression des caractès/chaîs indérables
dirnamefinal="$(echo "${dossier}" | sed -e 's/-[^-]*$//' | sed -e 's#\(.ANE\)##gi' | sed -e 's#\.# #g')"
#prise en compte de l'espace
final="$(echo ${dirnamefinal} | sed -e 's# #\ #g')"
#renommage effectif
mv "${i}" "${parent}/${final}"
echo "-->réltat : ${dirnamefinal}"
done
par contre, je pense que tu dois revoir ton expression sed -e 's/-[^-]*$//' car j'ai testé avec dossier nommé toto-titi qu'il m'a renommé en toto. Ca me parait un peu louche !
-- Lucid Lynx --
Hors ligne
#16 Le 23/06/2008, à 15:36
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Oke
Donc revoila mon script :
#!/bin/bash
#for i in /home/james/TEST/*/
for i in `find /home/james/TEST/ -type f -a ! -iregex "^.*[\ ]+.*$"`
do
#ne garder que le nom du répertoire
dirname=$(basename "$i")
#etape 1
echo "### traitement de $dirname"
#suppression des caractères/chaînes indésirables
dirnamefinal=$(echo "$dirname" | \
sed -e 's/-[^-]*$//' | \
sed -e 's#\(.ANE\|.PHOTO\)##gi' | \
sed -e 's#\.# #g' | \
sed -e 's#\_# #g')
#renommage effectif
mv $i "/home/james/TEST/$dirnamefinal"
echo "--> résultat : $dirnamefinal"
done
Donc au début j'avais
for i in /home/james/TEST/*/
que j'ai commenté pour essayer ta proposition.
Avec ce script, de n'importe où d'où je le lançais il me renommait les repertoires contenus dans /home/james/TEST/ afin de remplacer les "." et les "_" par des espaces, de supprimer certains termes, de couper le répertoire après le caractère "-" et d'afficher le résultat final.
Tout marchait bien excepté le fait qu'il me retourne une erreur pour tous les dossiers qui ont déjà été traités (donc qui contiennent un espace).
J'ai préféré mettre les différents sed sur différentes lignes par soucis de clarté (pour moi).
Voilà voilà
Merci encore
Dernière modification par spohyak (Le 23/06/2008, à 15:40)
Hors ligne
#17 Le 23/06/2008, à 15:43
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
nous avons du poster au même moment mais je t'ai devancé...
regarde mon poste juste avant le tiens.
Dernière modification par Totor (Le 23/06/2008, à 15:44)
-- Lucid Lynx --
Hors ligne
#18 Le 23/06/2008, à 16:26
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Héhé oke je vais tester ton script
Pour "par contre, je pense que tu dois revoir ton expression sed -e 's/-[^-]*$//' car j'ai testé avec dossier nommé toto-titi qu'il m'a renommé en toto. Ca me parait un peu louche !" C'est normal. Il doit virer le dernier "-" et tout ce qu'il y a après.
Toto-titi-tata donnera Toto-titi
Je poste le compte rendu et mes interprétation dans quelques minutes
Hors ligne
#19 Le 23/06/2008, à 16:32
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Bon ben j'ai envie de te dire qu'il va falloir que tu retournes à ton travail ennuyeux car le script marche comme sur des roulettes, dans tous les cas de figure
Merci beaucoup
Hors ligne
#20 Le 23/06/2008, à 16:40
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
Aie
J'ai parlé trop vite :
# mkdir /home/james/TEST/test.de-tirets.ane-OKE
# ./testor
-->résultat : test de-tirets
et
# mkdir /home/james/TEST/test.de-tirets2.ane-OKE
# ./testor
-->résultat : test de-tirets2
Impeccable puisque ca donne ça :
# ls -al /home/james/TEST/
drwxr-xr-x 2008-06-23 17:33 test de-tirets
drwxr-xr-x 2008-06-23 17:34 test de-tirets2
Mais :
# mkdir /home/james/TEST/test-de-tirets3.ane.toto-OKE
# ./testor
-->résultat : test-de-tirets3
# ls -al /home/james/TEST/
drwxr-xr-x 2008-06-23 17:33 test de-tirets
drwxr-xr-x 2008-06-23 17:34 test de-tirets2
drwxr-xr-x 2008-06-23 17:35 test-de-tirets3
Si on refait un coup de script, chose logique il va virer une fois encore les tirets puisqu'il n'a pas détecté d'espace dans le 3eme répertoire en fait c'est bien ça ?
# ./testor
-->résultat : test-de
# ls -al /home/james/TEST/
drwxr-xr-x 2008-06-23 17:35 test-de
drwxr-xr-x 2008-06-23 17:33 test de-tirets
drwxr-xr-x 2008-06-23 17:34 test de-tirets2
Si c'est juste pour cela, ça ne posera en fait pas de problème et tout roule sauf dans le cas où le nom du répertoire est un seul mot du type "toto" :
# ./testor
mv: ne peut déplacer `/home/james/TEST/test' vers un sous-répertoire de lui-même `/home/james/TEST/test/test'
-->résultat : test
Dernière modification par spohyak (Le 23/06/2008, à 17:00)
Hors ligne
#21 Le 23/06/2008, à 19:51
- Totor
Re : Finalisation d'un pti script pour renommer en série des répertoires
oui, effectivement, comme tu concerves des tirets, au prochain passage du script, il les traitera à nouveau.
pour éviter ceci, deux solutions me viennent immediatement à l'esprit :
1/ soit tu nommes tes nouveaux dossiers avec un prefix (ou suffixe) qui permettent d'identifier qu'ils ont déjà été traité. Auquel cas, tu filtres avec la commande find
2/ soit tu consignes les dossiers déjà traités dans un fichier, et là, tu filtres avec un grep
sinon, je te conseille de passer le dossier de travail en paramètre de ton script, c'est plus flexible :
#!/bin/sh
if [ $# -ne 1 ]; then
echo "Paramètre manquant : nom du dossier de travail"
exit 1
fi
rep="$1"
if [ ! -d "${rep}" ]; then
echo "${rep} n'existe pas ou n'est pas un dossier valide."
exit 2
fi
for i in `find ${rep} -maxdepth 1 -type d -a ! -iregex "^.*[\ ]+.*$"|sed -n '2,$p'`
do
#ne garder que le nom du rértoire
dossier="`basename ${i}`"
parent="`dirname ${i}`"
#etape 1
echo="***traitement de ${dossier}"
#suppression des caractès/chaîs indérables
dirnamefinal="$(echo "${dossier}" | sed -e 's/-[^-]*$//' | sed -e 's#\(.ANE\)##gi' | sed -e 's#\.# #g')"
#prise en compte de l'espace
final="$(echo ${dirnamefinal} | sed -e 's# #\ #g')"
#renommage effectif
mv "${i}" "${parent}/${final}"
echo "-->réltat : ${dirnamefinal}"
done
après, si t'en as le besoin, tu peux l'améliorer pour qu'il traite une liste de dossier et non un seul. c'est très facile
...mais je te laisse chercher pour ça.
-- Lucid Lynx --
Hors ligne
#22 Le 23/06/2008, à 22:18
- Alain.g
Re : Finalisation d'un pti script pour renommer en série des répertoires
Bonjour
▸ Concernant sed :
Quelque soit la façon choisie on peut écrire sur plusieurs lignes pour une meilleure lisibilité.
Le problème de ta méthode, ce n'est pas qu'elle est trop longue, mais qu'elle gaspille des ressources. Mais c'est vrai qu'ici ça ne fait pas grande différence.
Les parenthèses sont aussi inutiles dans ce cas. Ceci revient au même : #.ANE\|.PHOTO#
▸ find
for i in `find`
est une mauvaise méthode car les caractères spéciaux contenus dans les noms de fichiers seront interprétés comme des métacaractères.
Le problème le plus fréquent est avec les espaces, mais c'est loin d'être le seul possible. Si par exemple tu as un fichier se nommant "* étoile" et que tu recherches tous les fichiers contenant "étoile" dans leur nom de cette façon :
for i in `find -name '*étoile*'` ; do echo "$i" ; done
Tu auras en retour… tous les fichiers et non pas seulement ceux comportant "étoile", car "*" aura été interprété comme le caractère spécial.
Une meilleure façon est d'utiliser while read :
find -name '*étoile*' | while read -r i ; do echo "$i" ; done
ou mieux même si souvent inutile (les sauts de ligne étant rares dans les noms de fichiers) :
find -name '*.truc' -print0 | while read -rd $'\0' i ; do ... ; done
Pour le coup de la négation, on peut aussi l'utiliser avec -name, ce qui serait plus simple dans ce cas :
find -type d ! -name '* *'
À noter qu'en bash il est également possible de faire :
for i in /home/james/TEST/!(* *)/ ; do ... ; done
Dernière modification par Alain.g (Le 23/06/2008, à 22:19)
Xubuntu Karmic !
Hors ligne
#23 Le 24/06/2008, à 15:58
- spohyak
Re : Finalisation d'un pti script pour renommer en série des répertoires
sinon, je te conseille de passer le dossier de travail en paramètre de ton script, c'est plus flexible :
Merci, j'ai pris l'astuce pour information mais je ne pense pas l'utiliser car le script sera automatisé et lancé toujours pour le même emplacement. Donc si c'est "codé" dans le script ca suffira
après, si t'en as le besoin, tu peux l'améliorer pour qu'il traite une liste de dossier et non un seul. c'est très facile
...mais je te laisse chercher pour ça.
Du coup je n'ai pas besoin de chercher
Le problème de ta méthode, ce n'est pas qu'elle est trop longue, mais qu'elle gaspille des ressources. Mais c'est vrai qu'ici ça ne fait pas grande différence.
Les parenthèses sont aussi inutiles dans ce cas. Ceci revient au même : #.ANE\|.PHOTO#
Oke c'est bien noté et corrigé (pour les parenthèses), pour le reste les ressources ne doivent pas être énormes je pense.
À noter qu'en bash il est également possible de faire :
for i in /home/james/TEST/!(* *)/ ; do ... ; done
J'ai pris cette solution qui reste relativement simple
Merci à vous deux !
Hors ligne