Renommer des fichiers en masse

25

J'ai un certain nombre de fichiers:

10.3.100.179_01_20161018_230014_5335.jpg
10.3.100.179_01_20161018_231514_0814.jpg
10.3.100.179_01_20161018_233014_5706.jpg
10.3.100.179_01_20161018_234514_0896.jpg
10.3.100.179_01_20161018_230114_5395.jpg
10.3.100.179_01_20161018_231614_1145.jpg
10.3.100.179_01_20161018_233114_6047.jpg
10.3.100.179_01_20161018_234614_0547.jpg
10.3.100.179_01_20161018_230114_5492.jpg
10.3.100.179_01_20161018_231614_1264.jpg
10.3.100.179_01_20161018_233114_6146.jpg
10.3.100.179_01_20161018_234614_0658.jpg
10.3.100.179_01_20161018_230214_5630.jpg
10.3.100.179_01_20161018_231714_7135.jpg

Je veux renommer avec ce format:

10.4.100.135_01_20161013131108389_TIMING.jpg
10.4.100.135_01_20161013131111390_TIMING.jpg
10.4.100.135_01_20161013131114401_TIMING.jpg
10.4.100.135_01_20161013131117431_TIMING.jpg
10.4.100.135_01_20161013131120418_TIMING.jpg
10.4.100.135_01_20161013131123461_TIMING.jpg
10.4.100.135_01_20161013131126511_TIMING.jpg

Il doit supprimer l' _horodatage in et ajouter le _TIMING.

Jojo Mendoza
la source
5
Veuillez utiliser des exemples cohérents dans vos questions. Il semble que vous souhaitiez le remplacer 10.3.100.179par 10.4.100.135. Est-ce ce que vous voulez ou voulez-vous simplement supprimer le _TIMINGet le _du temps?
terdon
3
Un bon moment pour rappeler aux gens qu'il existe une norme iso8601 pour les dates (qui fonctionnent à la fois pour les noms de fichiers ET pour les entrées de journal) ^^ Donc, vous devriez peut-être reconsidérer le changement de nom pour devenir: AAAA-MM-JJThh: mm: ss.mmm (ex : votre premier fichier deviendrait: 10.4.100.135_01_2016-10-13T13:11:08.389_TIMING.jpg(et "TIMING" pourrait alors même être supprimé, car il ressemble désormais clairement à une date et une heure (et des millisecondes), surtout lorsque la norme devient plus répandue. Le T fait partie de la norme et je a grandi pour l'aimer (et le retirer brise la norme ^^)
Olivier Dulac
@OlivierDulac Je ne recommanderais pas d'utiliser :un nom de fichier. Je crois que Windows ne le prend pas en charge.
Justin
@Justin bon point. la norme recommande de le supprimer pour les noms de fichiers. J'ai donné la version en fichier
Olivier Dulac

Réponses:

38

Installez renameutilset utilisez qmvavec votre éditeur de texte préféré.

qmvcharge tous les noms dans votre éditeur et lorsque vous enregistrez et fermez, il applique vos modifications aux fichiers réels. Si les changements sont incohérents (par exemple, deux fichiers ont le même nom), ils seront abandonnés sans rien toucher. Il gère également correctement les renommages circulaires.

Je fais habituellement:

$ qmv -f do

de sorte qu'il affiche une seule colonne de noms (faire: destination uniquement). Voici à quoi ça ressemble:

qmw

Si vous le combinez avec les multiples curseurs de SublimeText, Atom ou Visual Studio Code, cela fait un outil très agréable et puissant pour renommer en masse. Par exemple, pour Atom, vous le feriez EDITOR="atom -w" qmv -f do.

ateijelo
la source
1
Bienvenue sur askUbuntu! C'est trop cool!
αғsнιη
Je l'ai signé juste pour +! il. ;)
J. Allan
2
Wow, bel outil et belle animation GIF. Grande première réponse, soyez les bienvenus! :)
Byte Commander
1
Merci @KasiyA d'avoir inclus l'image et merci à tous les autres pour les commentaires positifs.
ateijelo
1
@kasperd Oui, il avertira que le plan de renommage contient des erreurs et ouvrira une console interactive où d'autres actions peuvent être prises.
ateijelo
27

Utilisez rename...

rename -n 's/^([0-9]+\.[0-9]\.[0-9]+\.[0-9]+_[0-9]+_)([0-9]+)_([0-9]+)_([0-9]+)\.jpg/$1$2$3$4_TIMING\.jpg/' *

Avec -ncela affichera ce qu'il va faire sans apporter de modifications:

rename(10.3.100.179_01_20161018_230014_5335.jpg, 10.3.100.179_01_201610182300145335_TIMING.jpg)
rename(10.3.100.179_01_20161018_231514_0814.jpg, 10.3.100.179_01_201610182315140814_TIMING.jpg)
rename(10.3.100.179_01_20161018_233014_5706.jpg, 10.3.100.179_01_201610182330145706_TIMING.jpg)
rename(10.3.100.179_01_20161018_234514_0896.jpg, 10.3.100.179_01_201610182345140896_TIMING.jpg)

S'il semble correct, retirez le -n

$ rename 's/^([0-9]+\.[0-9]\.[0-9]+\.[0-9]+_[0-9]+_)([0-9]+)_([0-9]+)_([0-9]+)\.jpg/$1$2$3$4_TIMING\.jpg/' *
$ ls
10.3.100.179_01_201610182300145335_TIMING.jpg  10.3.100.179_01_201610182330145706_TIMING.jpg
10.3.100.179_01_201610182315140814_TIMING.jpg  10.3.100.179_01_201610182345140896_TIMING.jpg

Expliquant ...

  • s/something/something_else/ rechercher et remplacer
  • ^ le début du nom (ancrage)
  • [0-9] n'importe quel chiffre
  • + un ou plusieurs des caractères précédents
  • \.littéral .(sans que \cela corresponde à aucun caractère)
  • () garder cette partie
  • $1$2$3$3 retour des références aux choses appariées plus tôt et conservées avec ()

Remarque: *à la fin de la commande correspond tous les fichiers visibles dans le répertoire en cours. Utilisez un globe plus approprié si nécessaire.

Zanna
la source
2
Sur certaines distributions, cette commande est disponible sous la forme prename(p pour perl, car le premier argument est une expression perl)
Peter Cordes
12

mmv peut le faire comme suit:

mmv '*_*_*_*_*.jpg' '#1_#2_#3#4#5_TIMING.jpg'

10.3.100.179_01_20161018_230014_5335.jpg 10.3.100.179_01_201610182300145335_TIMING.jpg

# 1, # 2, # 3, ... fait référence à chacun au '*' correspondant ici.

Il est encore plus court avec:

mmv '*_*_*.jpg' '#1#2#3_TIMING.jpg'
αғsнιη
la source
9

Une autre renameapproche:

$ rename -n 's/(.*)_(.*)_(.*)\./$1$2$3_TIMING./' *
10.3.100.179_01_20161018_230014_5335.jpg -> 10.3.100.179_01_201610182300145335_TIMING.jpg
10.3.100.179_01_20161018_230114_5395.jpg -> 10.3.100.179_01_201610182301145395_TIMING.jpg
10.3.100.179_01_20161018_230114_5492.jpg -> 10.3.100.179_01_201610182301145492_TIMING.jpg
10.3.100.179_01_20161018_230214_5630.jpg -> 10.3.100.179_01_201610182302145630_TIMING.jpg
10.3.100.179_01_20161018_231514_0814.jpg -> 10.3.100.179_01_201610182315140814_TIMING.jpg
10.3.100.179_01_20161018_231614_1145.jpg -> 10.3.100.179_01_201610182316141145_TIMING.jpg
10.3.100.179_01_20161018_231614_1264.jpg -> 10.3.100.179_01_201610182316141264_TIMING.jpg
10.3.100.179_01_20161018_231714_7135.jpg -> 10.3.100.179_01_201610182317147135_TIMING.jpg
10.3.100.179_01_20161018_233014_5706.jpg -> 10.3.100.179_01_201610182330145706_TIMING.jpg
10.3.100.179_01_20161018_233114_6047.jpg -> 10.3.100.179_01_201610182331146047_TIMING.jpg
10.3.100.179_01_20161018_233114_6146.jpg -> 10.3.100.179_01_201610182331146146_TIMING.jpg
10.3.100.179_01_20161018_234514_0896.jpg -> 10.3.100.179_01_201610182345140896_TIMING.jpg
10.3.100.179_01_20161018_234614_0547.jpg -> 10.3.100.179_01_201610182346140547_TIMING.jpg
10.3.100.179_01_20161018_234614_0658.jpg -> 10.3.100.179_01_201610182346140658_TIMING.jpg

Si cela semble fonctionner comme vous le souhaitez, supprimez le -n.

terdon
la source
5

Vous pouvez également utiliser les éléments suivants. Faites d'abord une sauvegarde de vos fichiers et essayez ceci:

find . -name "*.jpg" -type f -print0| while read -d $'\0' file
do
    #extension="${file##*.}"
    newfilename=$(echo "${file%.*}" | sed 's/\(.*\)_\(.*\)_/\1\2/')
    mv "$file" "$newfilename""_TIMING.jpg"
done

sed 's/\(.*\)_\(.*\)_/\1\2/')supprime les _caractères de l'horodatage.

Par exemple:

user@host$ ls -lart
total 8
drwxrwxr-x 6 user user 4096 Oct 21 10:21 ..
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230014_5335.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231514_0814.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233014_5706.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234514_0896.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230114_5395.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231614_1145.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233114_6047.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234614_0547.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230114_5492.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231614_1264.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233114_6146.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234614_0658.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230214_5630.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231714_7135.jpg
drwxrwxr-x 2 user user 4096 Oct 21 10:30 .

user@host$ find . -name "*.jpg" -type f -print0 | while read -d $'\0' file
> do
>  newfilename=$(echo "${file%.*}" | sed 's/\(.*\)_\(.*\)_/\1\2/')
>  mv $file $newfilename"_TIMING.jpg"
> done

10:35:20 t $ ls -lart
total 8
drwxrwxr-x 6 user user 4096 Oct 21 10:21 ..
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182300145335_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182315140814_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182330145706_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182345140896_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182301145395_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182316141145_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182331146047_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182346140547_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182301145492_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182316141264_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182331146146_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182346140658_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182302145630_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182317147135_TIMING.jpg
drwxrwxr-x 2 user user 4096 Oct 21 10:35 .
Mustafa DOGRU
la source
1
C'est la meilleure solution. Bien sûr, l'âme de Zanna est parfaite pour quelques fichiers, mais comme la globalisation est effectuée par le shell, leur solution peut échouer sur un grand nombre de fichiers (chaîne de commande trop longue).
rexkogitans
@rexkogitans: Si vous utilisez un système Linux moderne (c'est-à-dire n'importe quelle version d'Ubuntu), la limite de la longueur de la ligne de commande est de plusieurs mégaoctets. Et si c'est un problème, vous pouvez utiliser find -maxdepth 1 -exec rename ... {} +pour regrouper la liste du répertoire en cours sur la ligne de commande de renommer. (ajoutez -name *.jpgou ce que vous voulez). Cela s'exécutera beaucoup plus rapidement qu'une boucle shell qui bifurque + les exécutables sedet mvpour chaque nom de fichier, au lieu d'un simple appel système de renommage. (Vous pourriez vous débarrasser de l' sedutilisation des trucs regex intégrés de bash, mais la fourche mvest toujours lente.)
Peter Cordes
2

Vous avez probablement terminé, mais voici une (toute) bashsolution toute simple : la
"solution simple ... bash" est-elle un oxymore?

#!/bin/bash

#loop through all files ending in .jpg
for f in *.jpg;
do

    #cut out everything to the timestamp
    firsthalf=${f%_*_*_*}

    #get from the timestamp on
    lasthalf=${f#*_*_}

    #remove (all) underscores from timestamp
    #note the 2 forward slashes...
    lasthalf=${lasthalf//_/}

    #get our extension
    ext=${lasthalf##*.}

    #now we can remove the extension
    lasthalf=${lasthalf%.*}

    #rename the file
    #change `mv` to `echo` if you want to do a trial run first...
    mv "$f" "${firsthalf}_${lasthalf}_TIMING.${ext}"

done;

PS: La logique de la boucle a été testée avec l'un de vos exemples de noms de fichiers. C'est passé.

J. Allan
la source
1
Il vaut probablement mieux utiliser un regex bash avec [[ $f ~= (.*)_(.*)_(.*)_(.*)\.jpg ]]; newname=${BASH_REMATCH[1]${BASH_REMATCH:2:4}TIMING.jpgou quelque chose. (totalement non testé et probablement faux, mais l'idée générale est que les groupes de capture entrent dans le tableau BASH_REMATCH.)
Peter Cordes
@PeterCordes: C'est un bon point! Je n'ai jamais utilisé ( bash) pour capturer des groupes, et pour être parfaitement honnête, bash n'est pas la première langue avec laquelle je les essayerais. (Je pense que bashc'est une langue laide.) Pourtant, c'est une bonne solution et cela m'a appris quelque chose de si bravo.
J. Allan
Oui, la principale raison de faire autant de traitement de texte en pure bash est lors de l'écriture de fonctions de tabulation qui devraient être rapides. Il apporte un tout nouveau sens à l'expression "code laid" ...
Peter Cordes
@PeterCordes: Je comprends votre argument, bien que je ne pense pas que le code soit "moche". Ce n'est peut-être pas la solution à 2 lignes que vous avez donnée, mais ce n'est pas difficile à lire en ce qui me concerne; en plus c'est bien commenté ...
J. Allan
Je parlais du code de complétion bash en général laid (ou du moins difficile à lire). En fait, ce n'est pas vraiment moche, juste un peu hallucinant (par exemple, passer des arguments par ref dans bash fait en passant un nom de variable et en faisant appel à l'appelé printf -v "$3" ...pour définir la variable dont le nom est $3dedans.) Démonter la ligne de commande entière et la remettre ensemble est assez difficile à suivre / déboguer, au moins je l'ai trouvé de cette façon en essayant de le nettoyer / corriger les bugs. Voir le code sur github
Peter Cordes
1

Si vous pouviez utiliser l'interface graphique, je recommanderais pyRenamer .

Il est présent dans la plupart des distributions, fi dans Ubuntu:

sudo apt-get install pyrenamer

Il peut faire tout ce que vous voulez et plus encore.

  • Il peut utiliser des modèles, ajouter ou supprimer du texte.
  • Il peut accéder aux données EXIF ​​si vous renommez des photos, vous pouvez donc générer des modèles basés sur la date / l'heure, etc.
  • Peut utiliser certaines métadonnées si vous renommez des fichiers musicaux.
  • De plus, il a un aperçu , ce qui peut éviter certaines erreurs difficiles à inverser.
jrierab
la source
Au votant ... Vous voulez bien expliquer pourquoi? OP n'a pas spécifié si l'interface graphique était une option ou non. Je vois que la plupart des réponses vont à la manière console / script, mais de nombreux utilisateurs apprécieront une solution GUI. Ou peut-être que pyRenamer a un défaut que je ne connais pas. En tout cas, j'aime bien connaître les raisons des downvotes.
jrierab
Puis-je également suggérer Thunar Bulk Renamer pour une approche graphique interactive interactive accrocheuse.
Tony Martin
@TonyMartin Cela devrait être un commentaire sous question, cela n'a rien à voir avec la réponse
Sergiy Kolodyazhnyy
0

Voici votre + + + oneliner brut intégré (love oneliners):findxargssedmv

find . -name "*.jpg" -print0 | sort -z | xargs -0 sh -c 'for filename; do mv "$filename" $(echo "${filename}" | sed "s/\([0-9]\{8\}\)_\([0-9]\{6\}\)_\([0-9]\{4\}\)/\1\2\3_TIMING/g"); done' sh

Explication:

  • find . -name "*.jpg" | sort | xargs sh -c <command> sh : liste tous les JPEG du répertoire courant puis exécutez une commande shell pour chacun (le tri est optionnel bien sûr, mais gardez les choses un peu plus propres si vous vous connectez quelque part)

  • -print0, -z, -0: Il est bonne habitude à des éléments séparés avec binaire 0lorsque tokenizing noms de fichiers pour éviter les problèmes avec in-the-middle-espaces blancs (pas votre cas si)

  • mv "$filename" $(echo "${filename}" | sed "s/\([0-9]\{8\}\)_\([0-9]\{6\}\)_\([0-9]\{4\}\)/\1\2\3_TIMING/g");: (Antislashs dans le sed« s regex ne contribuent pas à sa lisibilité, mais il est facile) renommer chaque fichier en remplaçant la séquence underscore-separeted de 8 + 6 + 4 chiffres avec leur concaténation contiguë , plus cette _TIMINGchose ( \iest un backreference au i- th regex group).


Réfs : Xargs - homme sed

Campa
la source