Comment renommer des fichiers dans un répertoire tout en conservant une partie du nom?

2

J'ai plusieurs fichiers (environ 1000) nommés comme tels:

abcdefg123456.xyz
abcdefg123457.xyz
abcdefg123458.xyz
abcdefg123459.xyz

Certains fichiers comportent 4 chiffres et lettres aléatoires supplémentaires (dans n'importe quel ordre) après le nom. Ce sont peut-être des doublons, mais pas toujours. Je dois donc les remplacer par le format d'origine pour vérifier s'ils sont en double ou non. Ils ont ce format:

abcdefg123456a789.xyz
abcdefg123457b987.xyz
abcdefg123458c879.xyz
abcdefg123459d897.xyz

À l’occasion, il existe également une mauvaise extension,

abcdefg123456.xyzedf
abcdefg123456.xyzfed

Je souhaite renommer ces fichiers au format original d'abcdefg suivi des 6 chiffres d'origine, c'est-à-dire supprimer les 4 chiffres et lettres aléatoires suivants et effacer l'extension finale .xyz Ce que j'ai pour l'instant est le suivant:

rename -n "s/[a-z][0-9]{6}.xyz/.xyz/g"  *

Mais cela ne semble pas fonctionner. Pour une raison quelconque, le résultat est:

abcdef.xyz (no numbers)

EDIT: J'étais un peu déchiré entre quelle réponse choisir, parce que les deux ont aidé à trouver la solution. Je suis allé chercher des arguments, car il a également contribué à la deuxième partie de la question. Mais votre aide est également grandement appréciée, Mark Perryman - et les commentateurs également, bien sûr.

utilisateur681866
la source
Votre principale erreur est l'utilisation de {6}chiffres: cela devrait être pour vos exemples {3}. Pour supprimer des caractères supplémentaires après le, .xyzvous devez ajouter .*à la fin de la chaîne de correspondance, en donnant rename -n "s/[a-z][0-9]{3}\.xyz.*/.xyz/g" *la commande (en omettant le -nmoment où vous êtes satisfait des actions).
AFH
Je vois. Je capturais la partie que je veux conserver, au lieu de la partie que je veux supprimer. Comment pourrais-je supprimer les fichiers s'ils ne peuvent pas être renommés? et si l'ordre des numéros et des lettres est pas exactement ...a789.xyz, ...b987.xyzmais suivent un schéma aléatoire au lieu: ...a7b8.xyz, ...c9d7.xyz. Merci.
user681866
Si le premier des caractères supplémentaires est une lettre, il le rename -n "s/[a-z][a-z0-9]{3}\.xyz.*/.xyz/g" *fera. Sinon, vous ne pouvez pas simplement utiliser [a-z0-9]{4}le modèle de correspondance, car cela supprimera les quatre derniers chiffres des fichiers au format standard et vous devrez utiliser des groupes de correspondance, comme dans les réponses, bien que vous puissiez essayer rename -n "s/[a-z0-9]{4}\.xyz.*/.xyz/g" ?????????????????.xyz*(17 requêtes), qui ne devrait traiter que les noms de fichiers les plus longs. Notez la différence entre la correspondance d'expression régulière et l'expansion de fichier shell.
AFH
Ma réponse mise à jour (utilisant des guillemets simples pour permettre à $ de fonctionner) et l'option -f permettant de supprimer les doublons sont une solution plus simple sur une ligne ;-)
Mark Perryman le

Réponses:

2

Solution

Pour supprimer les 4 chiffres / lettres précédant l’arrêt complet de tous les fichiers, vous pouvez utiliser la boucle suivante:

for file in *.xyz ; do
    NEWFILE=$(echo "$file" |sed -re 's/[a-z|0-9][a-z|0-9][a-z|0-9][a-z|0-9](\.)/\./g')
    mv -v $file $NEWFILE
done

Explication

for file in *.xyz ; do

Parcourt chaque fichier avec une extension .xyz

NEWFILE=$(echo "$file" |sed -re 's/[a-z|0-9][a-z|0-9][a-z|0-9][a-z|0-9](\.)/\./g')

Créez une variable appelée NEWFILEcontenant le nom du fichier après avoir supprimé un motif correspondant [a-z|0-9][a-z|0-9][a-z|0-9][a-z|0-9](mélange de 4 chiffres ou de lettres) et suivie d'un point final ( (\.)).

mv -v $file $NEWFILE

Déplacez le fichier sous son nouveau nom, -vcela imprimera le processus de déplacement au format suivant

`abcdefg123456a789.xyz` -> `abcdefg123456.xyz`

Cela ne couvre pas actuellement la réparation des extensions, mais une solution similaire à celle décrite ci-dessus peut être utilisée, mais avec la commande sed sed 's/\.xyz.*/\.xyz/g'.

stuts
la source
Merci d'avoir répondu. La deuxième partie fonctionne très bien. Le premier bit n'est pas tellement cependant, car les 4 derniers chiffres / lettres aléatoires sont aléatoires et ne sont pas toujours sous la forme de [lettre] [3xnombre]. Parfois, il y a plus de lettres et l'endroit change aussi. Mais il est toujours 4. EDIT: en changeant de lieu, je veux dire que ce pourrait être [3xnumber] puis [1xletter]; ou [2xletter], [1xnumber], [1xletter] - mais toujours 4.
user681866
J'ai modifié ma solution pour qu'elle corresponde à tout modèle de lettres et de chiffres avant l'extension du fichier. Faites-moi savoir comment cela fonctionne pour vous :)
Stuts
Cela supprime cependant les 4 derniers chiffres / lettres, y compris ceux qui ont le abcdefg123456.xyzformat.
user681866
La (\.)commande in the sed implique qu'il s'agit du modèle lettre / chiffre lettre / chiffre lettre / chiffre lettre / chiffre point final. Mes tests montrent que cela fonctionne. Existe-t-il des points d'arrêt complets dans les noms de fichiers autres qu'avant l'extension de fichier?
Stuts
Non, il n'y en a pas. Mais j'ai trouvé la solution en combinant votre méthode et celle de Mark ci-dessus: for file in *.html ; do NEWFILE=$(echo "$file" |sed -re 's/([a-z]*[0-9]{6})[a-z0-9]{0,4}(\.html).*/\1\2/g'); mv -v $file $NEWFILE; doneAu moins, le test initial sur 50 fichiers semble donner de bons résultats. Je pense, bien que corrigez-moi si je me trompe, que les [a-z|0-9]4 chiffres saisis avant de s'arrêter également, c’est pourquoi il modifie tous les fichiers originaux au abcdefg12format.
user681866
1

Essayer

rename -n -f 's/([a-z]*[0-9]{6})[a-z0-9]{0,4}(\.xyz).*/$1$2/g'  *

Cela fonctionne sur la version de renamepubliée avec debian et ubuntu (voir la page de manuel à http://www.computerhope.com/unix/rename.htm )

Cela écrasera les fichiers qui auraient autrement des noms en double.

Pourquoi ça marche

  • ([a-z]*[0-9]{6})est l'abcdefg123456 capturé et peut être appelé $1dans le remplacement.
  • (\.xyz)est l'extension capturée et appelée $2dans le remplacement.
  • Tout le reste [a-z0-9]{0,4}(jusqu'à 4 lettres / chiffres) et .*(tout ce qui suit l'extension) est mis en correspondance et ensuite ignoré dans le remplacement.

Bonus Pour supprimer tous les fichiers qui ne correspondent toujours pas à votre modèle (par exemple, si vous n'avez pas utilisé l'option de force ci-dessus), utilisez-les findpour les lister et les supprimer. (Exécuter sans -exec rm {}pour un essai à sec.)

find . -regextype posix-egrep -regex '.*/[a-z]*[0-9]{6}[a-z0-9]{4}\.xyz.*|[a-z]*[0-9]{6}\.xyz.*' -exec rm {}
Mark Perryman
la source
1
Strictement, l' .xyzexpression dans la recherche devrait être \.xyz, bien .qu'elle corresponde bien sûr à un littéral .ainsi qu'à tout autre caractère. L'expression originale du questionneur fonctionnera comme vous le faites, mais uniquement sur les noms de fichier sans les caractères supplémentaires; les noms avec les caractères supplémentaires ne seront pas affectés.
AFH le
Merci d'avoir répondu. Pour une raison quelconque, j'obtiens des erreurs en essayant cela. \ 1 vaut mieux écrire $ 1 à (eval 1) ligne 1. En outre, quand il ne peut pas renommer le nom de fichier car il existe déjà, il le conserve. Je sais que je n'ai pas demandé cela dans OP, mais comment pourrais-je le faire supprimer ce fichier?
user681866
Essayez s/([a-z]*[0-9]{6})[a-z0-9]{0,4}(\.xyz).*/$1$2/g?
Mark Perryman
Pour la suppression, vérifiez man renames'il existe une forceoption ou similaire. Sinon, exécutez une commande distincte qui supprime les fichiers qui ne correspondent toujours pas au format. Quelque chose comme find . -regextype posix-egrep -regex '[a-z]*[0-9]{6}[a-z0-9]{4}\.xyz.*|[a-z]*[0-9]{6}\.xyz.*' -exec rm {}mais RUN SANS -exec rm {}PREMIER!
Mark Perryman
Merci Mark, mais ça n'a pas marché. Le premier (remplaçant \ 1 \ 2 par $ 1 $ 2) m’a donné une erreur: No such file or directorypour tous les fichiers (avec \ 1 \ 2 cela ferait le travail, tout en donnant les erreurs). La deuxième suggestion n'a rien fait. Je n'ai pas essayé de courir avec-exec rm {}
user681866