Renommer plusieurs fichiers à l'aide de scripts Bash

27

Je veux renommer plusieurs fichiers dans le même répertoire à l'aide de scripts Bash. Les noms des fichiers sont les suivants:

file2602201409853.p
file0901201437404.p  
file0901201438761.p  
file1003201410069.p  
file2602201410180.p

Je souhaite renommer le format suivant:

file2503201409853.p
file2503201437404.p  
file2503201438761.p  
file2503201410069.p  
file2503201410180.p

Je lisais sur la commande renommer, et j'essaye de le faire de cette façon, mais ça ne fait rien, je pense que j'ai des questions sur la syntaxe. Ensuite, j'ai lu que vous pouvez faire une boucle en utilisant la commande mv comme suit:

for file in cmpsms*2014*.p; do
    mv "$file" "${file/cmpsms*2014*.p/cmpsms25032014*.p}"
done

Mais je ne peux pas renommer les fichiers. Qu'est-ce que je fais mal?

franvergara66
la source
2
Vous ne pouvez pas avoir une expression de modèle sur le côté droit d'une expression de remplacement d'extension de paramètre. À quoi vous attendiez-vous *?
kojiro
@Kiwy Cette question concerne la suppression d'une partie du nom de fichier. Ergo, doublon très douteux.
un CVn du
2
La prochaine fois, veuillez décrire les changements de nom de fichier que vous souhaitez apporter (j'ai dû regarder cela pendant un bon moment avant de voir les différences et les similitudes). Les exemples sont bons, mais une description ainsi que des exemples sont encore meilleurs.
un CVn du

Réponses:

42

Vous aviez raison d'envisager de renommer en premier. La syntaxe est un peu étrange si vous n'êtes pas habitué aux expressions régulières, mais c'est de loin l'itinéraire le plus rapide / le plus court une fois que vous savez ce que vous faites:

rename 's/\d{4}/2503/' file*

Cela correspond simplement aux 4 premiers chiffres et les échange pour ceux que vous avez spécifiés.

Et un harnais de test ( -vnsignifie être verbeux mais ne faites rien) en utilisant vos noms de fichiers:

$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
Oli
la source
8
Notez qu'il s'agit du renommage Perl sur Debian et ses dérivés (Ubuntu, Mint,…). Sur d'autres distributions Linux, renameest un outil de changement de nom de fichier complètement différent (sous lequel Debian est fourni rename.ul).
Gilles 'SO- arrête d'être méchant'
Si votre manque de distribution d'un tel outil, regardez @Michael Campbell répondre. Je pense que chaque distribution remplace le défaut renamecomme Debian.
Astery
25

Cela devrait faire l'affaire:

for f in file*; do mv $f ${f/${f:4:8}/25032014}; done

Il remplace la chaîne entre le 4ème et le 12ème caractère par "25032014".

le chaos
la source
cela for f in file*; do mv $f ${f/${f:4:4}/2503}; donefonctionne aussi.
Avinash Raj
C'est bien. Si vous voulez simplement remplacer un mot par un mot, cela fonctionne comme sed. par exemplefor f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Eric
1
@Eric - J'ai posté votre réponse comme alternative car je pense qu'elle est plus claire et élégante. Si vous souhaitez également le poster en tant que réponse - je supprimerai le mien. Merci!
Yehosef
Pourquoi les doubles guillemets manquants ?
Wildcard
Cela me donne une erreur: "mv: la cible 'FILE_NAME' n'est pas un répertoire"
Aubrey
10

c'est vraiment la réponse d'Eric d'en haut - mais c'est une réponse élégante, donc je la republie comme une réponse appropriée pour attirer plus l'attention sur elle.

for f in *Huge*; do mv $f ${f/Huge/Monstrous}; done
Yehosef
la source
1
ptrn='file[0-9][0-9][0-9][0-9]2014[0-9][0-9][0-9][0-9][0-9].p'
path=/dir
( set -- "${path}/"${ptrn} ; for f ; do {
    echo "mv ${path}/${f} \
        ${path}/file25032014${f#2014}" 
} ; done )

Cela devrait faire l'affaire. Remarque - Je n'ai pas l'habitude de remettre des commandes mv de masse - comme écrit, ce n'est qu'un écho. Vous devrez trier cela avant que cela fonctionne.

mikeserv
la source
1

Une façon native simple de le faire sans boucle, avec traversée de répertoire :

find -type f | xargs -I {} mv {} {}.txt

Il renommera chaque fichier en place.

Et ci-dessous un exemple de travail avec parallélisation :

find -name "file*.p" | parallel 'f="{}" ; mv -- {} ${f:0:4}2503${f:8}'
dtrckd
la source
C'était une première approche facile pour imaginer une meilleure solution. Si vous voulez une commande qui fonctionne, faites:
dtrckd
find -type f -name "file*.p" | parallel 'ext="{}" ; mv -- {} ${ext:0:4}2503${ext:8}'
dtrckd
0

Si vous constatez que vous faites souvent ce genre de choses, recherchez "rename.pl". C'est un script perl, mais vous permet simplement de lui donner du code perl (comme une expression ///), et il fera un renommage en masse basé sur cette expression ou ce code.

Il existe une version de base ici: http://stackoverflow.org/wiki/Rename.pl mais il existe d'autres versions flottant sur le net. Il existe depuis des siècles et des âges et des âges.

Michael Campbell
la source