Considérez cette list de files:
$ touch index-{1,2,3,4,5,6,7,8,9}.txt
Si je veux les déplacer vers le bas afin qu'ils commencent à zéro, c'est relativement facile :
$ rename --verbose 's/^index-([1-9])\.txt$/$1/; $_="index-" . ($_ - 1) . ".txt"' index-*.txt
Cela fonctionne car man bash
spécifie que les globs sont sortingés alphabétiquement, donc il renommera index-1.txt
en index-0.txt
avant de renommer index-2.txt
en index-1.txt
.
Cela se décompose si vous voulez déplacer vers le haut , ou si les numbers ont des longueurs différentes :
$ touch index-{10,11}.txt $ rename --verbose 's/^index-([0-9]+)\.txt$/$1/; $_="index-" . ($_ + 1) . ".txt"' index-*.txt index-10.txt not renamed: index-11.txt already exists index-11.txt renamed as index-12.txt index-1.txt not renamed: index-2.txt already exists
Corrections possibles à long terme:
rename
pour essayer de réorganiser les opérations jusqu'à ce qu'il n'y ait pas de collision. rename
pour déplacer d'abord les files vers un directory temporaire, puis les déplacer avec le nouveau nom. Y a-t-il un moyen simple de contourner ce problème?
La solution @ l0b0 réécrite pour une meilleure robustesse:
printf '%s\0' index-*.txt | sort --zero-terminated --field-separator - --key 2rn | xargs -0r rename --verbose ' s/^index-([0-9]+)\.txt$/$1/; $_="index-" . ($_ + 1) . ".txt"'
N'hésitez pas à inclure dans votre solution et je supprimerai ma réponse par la suite.
Notez que les solutions de @ l0bo et de GNU sont spécifiques à GNU, et non Unix (GNU's Not Unix).
Il y a une petite command standard connue sur Unix qui peut nous aider ici à find une solution générale pour find dans quel ordre une série de tsort
doit être faite: tsort
Supposons que nous ayons une list de renoms à faire dans un file appelé renames.txt
(en supposant pour preuve que leur nom ne contient pas de blancs):
da ef be ac
Parce que d
doit être renommé en a
, cela signifie a
doit être renommé avant d
. Nous avons donc un ordre de sorting partiel qui serait l'inverse de l'ordre dans lequel les files devraient être renommés.
tsort est l'outil permettant d'inférer un ordre de sorting complet à partir d'une list d'ordres de sorting partiels. Il reviendrait avec une erreur s'il y avait une boucle qui nous aiderait à détecter les cas où il n'y a pas de solution. Si nous appliquons tsort sur cette input, cela nous donne:
b d e a f c
Ce qui dit que b
devrait être renommé après d
après e
. Nous pouvons utiliser GNU tac (certains systèmes ont aussi tail -r
) pour inverser cet ordre:
c f a e d b
Et rejoignez-le avec notre list de renoms:
tsort renames.txt | tac | awk ' NR==FNR { ren[$1] = $2 next } $1 in ren { print "mv -i --", $1, ren[$1] }' renames.txt -
qui nous donne:
mv -i -- ac mv -i -- ef mv -i -- da mv -i -- be
que nous pouvons ensuite canaliser à sh pour exécuter.
Notez cependant qu'il n'est pas robuste car nous ne vérifions pas l'état de sortie de tsort
ci-dessus pour détecter les loops, et les noms de files ne doivent pas contenir de caractères shell spéciaux.
La robustification est laissée comme un exercice au lecteur 😉
Cela fonctionne pour le cas spécifique ci-dessus:
rename --verbose 's/^index-([0-9]+)\.txt$/$1/; $_="index-" . ($_ + 1) . ".txt"' $(printf '%s\n' index-*.txt | sort --field-separator - --key 2n | tac)
Mais:
Pas une réponse directe à votre question car vous mentionnez bash, mais avec zsh, vous pouvez spécifier l'ordre de sorting et le sorting numérique avec des qualificatifs globbing.
$ echo index-*.txt index-12.txt index-1.txt index-2.txt index-4.txt $ echo index-*.txt(n) index-1.txt index-2.txt index-4.txt index-12.txt $ echo index-*.txt(nOn) index-12.txt index-4.txt index-2.txt index-1.txt
Ou vous pouvez définir votre propre ordre de sorting avec une fonction et utiliser l' index-*(o+that-function)
.
Notez également que zsh a sa propre fonction embeddede rename
appelée zmv
:
$ zmv -fvQ 'index-(<->).txt(n)' 'index-$(($1-1)).txt' mv -- index-1.txt index-0.txt mv -- index-2.txt index-1.txt mv -- index-4.txt index-3.txt mv -- index-12.txt index-11.txt $ zmv -fvQ 'index-(<->).txt(nOn)' 'index-$(($1+1)).txt' mv -- index-11.txt index-12.txt mv -- index-3.txt index-4.txt mv -- index-1.txt index-2.txt mv -- index-0.txt index-1.txt