Soustrayez 1 de tous les noms de fichiers (renommez-les) dans un répertoire.

17

J'ai un répertoire qui contient des fichiers image avec des noms comme

image1.jpg 
image2.jpg 
image3.jpg
...

Malheureusement, les noms d'images doivent être basés sur zéro, donc image1.jpgdevraient l'être image0.jpg, image2.jpgdevraient l'être image1.jpget ainsi de suite.

Je peux écrire un script pour générer des commandes mv comme celles-ci, les mettre dans un script shell, puis les exécuter -

mv image1.jpg image0.jpg
mv image2.jpg image1.jpg
mv image3.jpg image2.jpg
...

Mais je suppose qu'il existe une façon plus nette de le faire sous Unix. Alors c'est quoi?

Nous s
la source
6
C'est en fait la façon la plus simple de le faire, tant qu'il n'y a pas de lacunes. ( for i in $(seq 0 100); do mv image$[i+1].jpg image$i.jpg; done)
Ricky Beam
5
L'ordre des images est-il important? Sinon, renommez simplement la dernière image de imageN.jpgà image0.jpget vous avez terminé.
jnovacho
@jnovacho, assez intelligent! Mais oui, l'ordre des images est important.
Wes

Réponses:

20

Le bon vieux perl renommé:

rename 's/(\d+)(\.jpg)/($1-1).$2/e' *

[Remarques]

Le nombre d'images doit être supérieur à 0.

Dans le cas où les images sont supérieures à 9 et n'ont pas de 0 en tête, utilisez $(ls -v1 *)pour éviter le clobber. Proposé par @arielf et remarqué par @Graeme.

En cas de doute, utilisez également -vpour verbeux et -nsans action.


la source
Qu'est-ce que le «e» indique?
Wes
3
«e» signifie évaluer, la section de remplacement sera évaluée. voir aussiperlreref
6
Les fichiers doivent être passés dans l'ordre croissant pour éviter tout clobber. Cela ne fonctionnera correctement que s'il y a moins de 10 fichiers (ou si les nombres ont des zéros en tête).
Graeme
Je l'ai déjà remarqué, il ne doit pas non plus y avoir 0de sources.
2
remplacez le *à la fin par `ls -v1 *`et vous serez plus en sécurité contre le clobbering. Cela ira du nombre le plus bas au plus élevé.
arielf
6

Vous pouvez diriger le généré mv commandes vers bash. Vous n'avez donc pas à les copier dans un script et à les exécuter. Voir:

command_that_generates_mv_commands | bash

Et tout sera exécuté qui est canalisé bash.

le chaos
la source
Ce n'est pas plus net. :)Résout le problème, alors +1.
JMCF125
5

Vous pouvez parcourir la sortie ls, celle-ci fonctionne pour votre exemple:

i=0 
for file in $(ls *.jpg | sort) ; do 
     mv $file $(echo $file | sed 's/[0-9]*.jpg$/'${i}'.jpg/')
     i=$((++i))
done

Vous devez être sur le même chemin que vos fichiers

babasbot
la source
1
Mieux à utiliser -iou -navec mv, il empêchera l'écrasement dans les cas marginaux.
Graeme
ne serait pas sort -Vmieux à la place?
user80551
sortne fonctionnera pas, il montrera image10.jpgavant image1.jpgce qui pourrait être un problème. Vous avez besoin sort -nk 1.8comme dans la réponse de @ Graeme.
terdon
@ user80551, sort -Vest une bonne idée, l'ajoutera à ma réponse. Cependant, il pourrait y avoir d'autres cas marginaux, juste de bons conseils pour ajouter ce type d'options avec des questions comme celle-ci au cas où quelqu'un copierait et finirait par faire des dégâts.
Graeme
4

Ce qui suit semble fonctionner pour tout ce qui correspond au modèle imageNUMBER.jpg. J'ai placé echoavant la mvcommande pour montrer d'abord ce que la commande ferait; pour effectuer le changement de nom, supprimez simplementecho

for i in `ls image*.jpg|sort -V` ; do 
    x=`echo $i|sed -e "s/image\(.*\).jpg/\1/"`
    y=$(( $x - 1 ))
    echo mv -i $i image$y.jpg
done

Dans la première ligne, le ls image*.jpg|sort -Vfera apparaître les fichiers JPG avec des nombres ascendants dans le nom de fichier. La x=ligne extrait le numéro du nom de fichier. La y=ligne décrémente ensuite le nombre de un. Le nom de fichier d'entrée et le ynuméro sont ensuite utilisés dans la mvcommande, où le-i indicateur vous avertira avant d'écraser un fichier.

Pour mon propre petit test, cela a produit la sortie:

mv -i image1.jpg image0.jpg
mv -i image2.jpg image1.jpg
mv -i image123.jpg image122.jpg

Personnellement, je suggère de renommer un nom de fichier plus différent, car maintenant l'ordre dans lequel les fichiers sont traités peut faire une grande différence.

brm
la source
1
Mieux à utiliser -iou -navec mv, il empêchera l'écrasement dans les cas marginaux.
Graeme
Très bonne suggestion, je vais modifier la réponse
brm
Sous macOS, vous devez utiliser sort -n, l' -Voption n'existe pas.
Vincent Sit
4

L'utilisation du perlscript prename, dont le lien symbolique permet de renommer les distributions basées sur Debian, nécessite également GNU find/ sort. Les fichiers sont classés par ordre croissant pour éviter tout écrasement.

find . -regex '\./image[0-9]+\.jpg' -print0 | sort -zV |
  xargs -0 rename -n 's/(\d+)\.jpg$/@{[$1-1]}.jpg/'

Retirez-le -nune fois que vous êtes sûr qu'il fait ce que vous voulez. Avertira des fichiers déjà existants avant de le faire. Cependant, tant qu'il affiche les fichiers renommés dans l'ordre croissant, il n'y aura pas de conflits lorsqu'ils seront exécutés pour de vrai.

Graeme
la source
Le fichier existe déjà des problèmes avec celui-ci.
Wes
4

Avec zsh:

autoload zmv # (in ~/.zshrc)
zmv -Qf -n 'image(<->).jpg(n)' 'image$(($1-1)).jpg'

(retirer -n quand heureux).

(n)consiste à trier la liste numériquement afin qu'elle image9.jpgsoit renommée auparavant image10.jpg.

Stéphane Chazelas
la source