#1 Le 30/03/2020, à 19:26
- ladsy
bash regex - modification recursive de nom de fichier
Bonjour,
Je souhaite faire un script bash qui renomme une arborescence de fichiers selon tout un tas de petites règles à passer.
Mon gros problème est du type
find . -type f | rename 's/[ (1)]//' qui supprime tous les espaces de tous les noms de répertoires en plus du "(1)" ...
exemple :
- gicler les (1), (2) des anciens doublons qui n'en sont plus
- supprimer les "!", les "~", les "(" que le vulgus user crée dans ses fichiers word ou emails
- etc ...
Je ne veux pas de boucle while / for dans ce script ...
non, je n'en veux pas.
Mes commandes sont donc des regex (que je tente de commencer de comprendre), de l'usage de "rename", du "find", du "sed" (que j'entrave décidément pas depuis 3 h que je cherche) et du " | ".
Mes problèmes ...
Le plus gros :
Je n'arrive pas à faire comprendre à ma regex comment traiter non pas "chaque caractère" mais "une chaine". Notamment, la commande
find . -type f | rename 's/[ (1)]//gi'
... qui supprime tous les espaces de tous les noms de répertoires en plus du "(1)" ...
Je n'arrive pas à faire comprendre à "rename" (et d'ailleurs même sed), comment ne chercher que la chaîne " (1)" qui a "un espace" + "(1)" ... ou (2), etc ... à la fin du fichier. Je veux ici supprimer les doublons qu'a tendance à créer Google Drive quand il s'empêtre les synchronisations avec 3 PC connectés Windows au même google drive.
Et pour optimiser :
J'aurai bien aimé fusionner == find . -type f | rename 's/é/e/gi' == et == find . type f | rename 's/è/e/gi' == ... sans me retrouver avec ee dans le nom à chaque fois que j'ai un "é" ou un "è" ... Je crois que j'ai testé toutes les combinaisons de == find . type f | rename 's/[éè]/e/gi' == sans succès (cette combinaison écrit des "ee" à chaque "é" ou "è" et des "eeee" si le nom contient "éè" :-(
Précision, le système de fichier est ... ntfs / gvfs-fuse ... un répertoire Windows monté dans une machine virtuelle Ubuntu
Que fais-je donc ?
Je nettoie un Google-Drive, et une Dropbox lancée sous Windows 10 depuis une VM Ubuntu, et un disque dur de 2 To en 2 partitions (ntfs et ext4) monté quand à lui dans la dite VM Ubuntu
J'ai vu pas mal d'exemple avec des boucles type for / while etc (notamment sur ubuntu-fr et par ex https://forum.ubuntu-fr.org/viewtopic.php?id=296672 ) ... Je n'en veux pas. Car il faut que je puisse réemployer facilement une même commande, mais avec des paterns différents à chaque fois.
Merci d'avance pour votre aide.
ubuntu mate 21.04 x86-64 - dual boot W10
Machine 1 : portable Lenovo P50 - écran 4K - 4G/LTE - raid 0 de 2 eNVM - 64 Go de RAM et écran Acer Predator XB321HK
Machine 2 :P5Q-EM - 16Go - SB X-Fi Xtrem - 3 SSD Samsung 840EVO 500 Go en raid 0, GTX 970 et écran Samsung B2330
Hors ligne
#2 Le 30/03/2020, à 20:04
- kamaris
Re : bash regex - modification recursive de nom de fichier
Pour les bases concernant les regex, wikipédia est ton amie : https://fr.wikipedia.org/wiki/Expressio … li%C3%A8re
Ici, il te manque l'utilisation du « ou » logique (alternance) : « | ».
Par exemple, pour supprimer toutes les espaces et la chaine « (1) » :
find . -type f | rename 's/ |\(1\)//g'
Concernant les caractères accentués (donc non ascii), ils ne sont pas considérés comme des caractères mais comme des chaines, donc inéligibles à l'insertion dans des crochets.
Il faut aussi utiliser « | » :
find . -type f | rename 's/é|è/e/g'
Voir man pcresyntax : « In PCRE, POSIX character set names recognize only ASCII characters by default ».
Hors ligne
#3 Le 31/03/2020, à 09:21
- Hizoka
Re : bash regex - modification recursive de nom de fichier
Bonjour,
ne serait il pas mieux d’éviter le pipe et d'utiliser l'option -exec de la commande find ?
Ça ne répond pas à la question (kamaris l'a fait), mais c'est juste un conseil.
KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github
Hors ligne
#4 Le 31/03/2020, à 13:06
- kamaris
Re : bash regex - modification recursive de nom de fichier
Non, ce ne serait pas mieux, parce que -exec va appeler rename autant de fois qu'il y a de fichiers à renommer.
Même si on utilise la forme « -exec … + », ça va obliger find à fabriquer une ligne de commande (à la manière d'xargs), alors que rename est nativement capable de gérer un flux par l'entrée standard.
Ce qui aurait été bien, par contre, c'est de pouvoir passer à rename un flux délimité par des caractères nuls, mais je n'ai pas l'impression qu'elle sache gérer cela :
find . -type f -print0 | rename -0 's/é|è/e/g'
Hors ligne
#5 Le 31/03/2020, à 14:41
- Hizoka
Re : bash regex - modification recursive de nom de fichier
Pffff pour ce que ça change
Tests avec 1 000 fichiers, franchement, je m'attendais pas à une telle différence...
time find . -type f | rename 's/a/b/'
real 0m0,117s
user 0m0,074s
sys 0m0,025s
time find . -type f -exec rename 's/a/b/' {} \;
real 1m12,729s
user 1m1,320s
sys 0m7,344s
On oublie donc ce mauvais conseil
time find . -type f -exec rename 's/a/b/' {} +
real 0m0,097s
user 0m0,065s
sys 0m0,032s
Par contre avec +, ça marche très bien aussi.
Merci
Dernière modification par Hizoka (Le 31/03/2020, à 14:41)
KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github
Hors ligne
#6 Le 31/03/2020, à 17:37
- kamaris
Re : bash regex - modification recursive de nom de fichier
De rien, et merci pour les tests
Je viens de me rendre compte, en testant dans une vm ubuntu 19.10, que rename a bien une option --null ou -0, pour gérer le délimiteur nul dans son flux d'entrée.
Sous arch linux, je n'ai pas ça *
En tout cas, sous ubuntu (19.10 au moins), on peut bien faire
find . -type f -print0 | rename -0 's/é|è/e/g'
--
* Ça n'est pas tout à fait la même commande en fait : pour avoir celle d'ubuntu, sous arch, il ne faut pas prendre celle des dépôts officiels (perl-rename), mais aller la chercher sur aur (file-rename).
Dernière modification par kamaris (Le 31/03/2020, à 17:51)
Hors ligne
#7 Le 31/03/2020, à 18:00
- marcus68
Re : bash regex - modification recursive de nom de fichier
Bonjour,
Bonjour,
Je souhaite faire un script bash qui renomme une arborescence de fichiers selon tout un tas de petites règles à passer.
Mon gros problème est du type
find . -type f | rename 's/[ (1)]//' qui supprime tous les espaces de tous les noms de répertoires en plus du "(1)" ...
c'est typiquement parce que tu as mis des crochets que ça a ce comportement.
tu peux utiliser ça pour enlever tous les (1) (2), ...
find . -type f | rename 's/ (.)//g'
et pour les autres caractères tu peux justement utiliser le crochet.
exemple :
find . -type f | rename 's/ (.)//g;s/[!~]//g'
rename peux également prendre une liste de fichier en argument, pourquoi utiliser find ?
je réfléchi encore à ton "optimisation"
Cordialement
Dernière modification par marcus68 (Le 31/03/2020, à 18:01)
Hors ligne
#8 Le 03/04/2020, à 11:48
- Ferod
Re : bash regex - modification recursive de nom de fichier
Bonjour
Pour remplacer caractère par caractère avec sed on peut utiliser "y" :
sebastien@focal:~$ echo éèàùê | sed 'y/éèàùê/eeaue/'
eeaue
sebastien@focal:~$
le principe c'est que le premier caractère é (juste après le y) est remplacé par le premier caractère de remplacement etc...
"When I was in the military, they gave me a medal for killing
two men, and a descharge for loving one !" Leonard Matlovich
Hors ligne
#9 Le 03/04/2020, à 12:00
- kamaris
Re : bash regex - modification recursive de nom de fichier
Avec sed oui, car elle gère les caractères codés sur plusieurs octets, mais pas avec rename :
$ touch é
$ ls
é
$ rename 'y/é/e/' *
$ ls
ee
$
Hors ligne