Essayer de faire de l'arithmétique dans Perl Rename Tool (Debian)

8

Supposons que j'ai cinq fichiers mp3:

01-trackfoo.mp3
02-trackbar.mp3
03-trackbaz.mp3
04-trackabc.mp3
05-trackxyz.mp3

Maintenant, j'écoute rapidement les fichiers (juste mplayer sur la console fera l'affaire) et je découvre que les pistes sont dans le mauvais ordre . 05 est en fait 02 et le reste devra être renommé. Donc, je vais d'abord faire un changement de nom temporaire:

01-trackfoo.mp3

02-trackbar.mp3
03-trackbaz.mp3
04-trackabc.mp3
00-trackxyz.mp3

Maintenant nous avons besoin d'un "shift": 02 devrait devenir 03, 03 devrait devenir 04 et 04 devrait devenir 05. Pour minimiser la confusion, ex-05 (maintenant 00) sera mvédité plus tard.

Mon approche était la suivante: (perl rename, par Larry Wall, par défaut ici sur Debian)

rename 's/0([2-4])([\s\S]+)/0($1+1)$2/' *

ainsi que (plus tard, après quelques RTFM supplémentaires)

rename 's/0([2-4])([\s\S]+)/0($1+1)$2/e' *

Aucun d'entre eux n'a fonctionné, en particulier parce que le /e[val]modificateur n'accepte rien d'autre que des évaluations et générera une erreur une fois que vous tenterez de combiner les évaluations avec des chaînes. Le bashpeut le faire très bien, par exemple foo$((1+6))sera évalué foo7.

Alors, comment puis-je faire cela (une ligne de préférence, sans avoir l'intention d'écrire un script autonome juste pour cela)?

erreur de syntaxe
la source

Réponses:

7

Tu l'as presque eu. Il vous suffit de rendre explicites les chaînes littérales et la concaténation de chaînes dans la /esubstitution -modified, en utilisant des guillemets et l'opérateur point.

rename 's/0([2-4])([\s\S]+)/"0".($1+1).$2/e' *
Alan Curry
la source
Il laisse l'original 05 toujours non renommé, mais +1 pour résoudre le problème d' une ligne .
Peter.O
1
(note mineure, renommer s'appelle prename dans Ubuntu) ... Si aucun nom dans le répertoire ne commence par $'\x01'2alors un renommage préliminaire comme celui-ci: prename 's/^05/\x012/' 05*.. puis le [2-4]renommer ci-dessus .. alors une finale prename 's/^\x01/0/' $'\x01'2*fera l'affaire .. Cela fait 3 un -liners ... Pour un quatrième, et une première vérification de la présence éventuelle d'un fichier commençant par $'\x01', quelque chose comme cet extrait de bash leshopt -s nullglob; x=($'\x01'*); [[ -n $x ]] && { echo '\x01' is not suitable; exit; }
piégera
OUI! Merci Alan, je n'ai pas pensé à cet opérateur de points, même si je savais quoi faire avec des mots lisibles par l'homme: "dis / e de ne pas toucher les trucs en dehors du ()" :) Et merci à Peter pour le bash approche aussi. De plus, si j'avais eu une idée de la proximité de la syntaxe PHP avec Perl, j'aurais probablement trouvé la solution par essais et erreurs. Parce que ce point EST l'équivalent JavaScript '+' en PHP pour la concaténation de chaînes.
erreur de syntaxe du
4

one-liner préféré, pas l'intention d'écrire tout un script autonome juste pour cela

Quand les choses deviennent si compliquées, je ne vois aucune raison de ne pas écrire de script. Vous ne vous souviendrez jamais de la façon de procéder d'une exécution à l'autre, vous finirez donc par la réinventer à chaque fois, ou tout de même dans un script.

Pour une petite chose comme ça, je commence généralement à essayer de le résoudre dans Bash:

#!/bin/bash
if [ -z "$1" ] ; then echo Need arguments. ; exit 1 ; fi

typeset -i i=1
for f in "$*"
do
    tailbits=`echo "$f" | sed -e 's/^[0-9]+//'`
    mv "$f" sertmp-`printf %02d $i`"$tailbits"
    i=i+1
done

for f in "sertmp-*"
do
    mv "$f" `echo "$f" | sed -e s/^sertmp-//` 
done

Fondamentalement, ce script supprime tous les premiers chiffres, puis met un numéro de série croissant à zéro au recto, avec les fichiers numérotés selon l'ordre dans lequel vous les passez au script.

Il le fait en deux étapes, avec des sertmp-préfixes pour la première passe pour éviter tout risque de collision de noms. Si vous appelez ce script mp3-renameret l'appelez comme:

$ mp3-renamer 01-foo.mp3 03-bar.mp3 04-qux.mp3

vous rencontrez une collision triviale lors du premier changement de nom si vous n'utilisez pas 2 passes pour effectuer le changement de nom. ( 01-foo.mp3-> 01-foo.mp3.)

Si vous l'appelez comme ceci, cependant:

$ mp3-renamer 02-foo.mp3 01-foo.mp3

vous effacez accidentellement 01-foo.mp3lors du premier changement de nom avec un changement de nom en 1 passe.

Si le problème devient plus compliqué, je le réécrirais en Perl. À ce stade, vous pouvez ensuite utiliser un hachage pour conserver le mappage de nom ancien-> nouveau, et utiliser un peu de code intelligent pour déterminer l'ordre approprié pour les renommer afin d'éviter la nécessité de 2 passes.

Warren Young
la source