Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#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 "è" sad  ... 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 smile
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 smile



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 lol

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 smile

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 smile

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 wink
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 sad *
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,

ladsy a écrit :

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