Cercando di fare l'aritmetica nello strumento di rinomina Perl (Debian)


8

Supponiamo di avere cinque file mp3:

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

Ora do un rapido ascolto ai file (solo mplayer su console farà il trucco) e scopro che le tracce sono nell'ordine sbagliato . 05 è in realtà 02 e il resto dovrà essere rinominato. Quindi prima farò un rinominazione temporanea:

01-trackfoo.mp3

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

Ora abbiamo bisogno di un "turno": 02 dovrebbe diventare 03, 03 dovrebbe diventare 04 e 04 dovrebbe diventare 05. Per ridurre al minimo la confusione, ex-05 (ora 00) verrà appena pubblicato in mvseguito.

Il mio approccio era questo: (perl rename, di Larry Wall, predefinito qui su Debian)

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

così come (più tardi, dopo alcuni altri RTFM)

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

Nessuno di loro ha funzionato, soprattutto perché il /e[val]modificatore non accetta nient'altro che valutazioni e genererà un errore quando si tenta di combinare le valutazioni con le stringhe. Il bashgrado di farlo bene, ad esempio, foo$((1+6))saranno valutate al foo7.

Quindi, come posso fare questo (preferendo una sola riga, non intendendo scrivere un intero script autonomo solo per questo)?

Risposte:


7

Ce l'hai quasi fatta. Devi solo rendere esplicite le stringhe letterali e la concatenazione delle stringhe all'interno della /esostituzione modificata, usando le virgolette e l'operatore punto.

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

Lascia lo 05 originale ancora non rinominato, ma +1 per risolvere il problema tecnico di una riga.
Peter

1
(minore nota, rename si chiama prename in Ubuntu) ... Se non nomi inizia directory con $'\x01'2poi una ridenominazione preliminare come questo: prename 's/^05/\x012/' 05*.. poi il sopra [2-4]rename .. poi una finale prename 's/^\x01/0/' $'\x01'2*farà il trucco .. che fa 3 uno -liners ... Per un quarto, e un controllo iniziale per la possibile presenza di un file che inizia con $'\x01', qualcosa come questo frammento di bash lo intrappolerà ..shopt -s nullglob; x=($'\x01'*); [[ -n $x ]] && { echo '\x01' is not suitable; exit; }
Peter.O

Yeees! Grazie Alan, non ho pensato a quell'operatore punto, anche se sapevo cosa fare in parole leggibili dall'uomo: "dì / e di non toccare le cose al di fuori del ()" :) E grazie a Peter per la bash anche approccio. Inoltre, se avessi avuto idea di quanto la sintassi PHP sia vicina a quella di Perl, probabilmente avrei trovato la soluzione per tentativi ed errori. Perché quel punto È la controparte JavaScript '+' in PHP per la concatenazione di stringhe.
syntaxerror,

4

one-liner preferiva, non intendendo scrivere un intero script autonomo solo per questo

Quando le cose si complicano, non vedo alcun motivo per non scrivere una sceneggiatura. Non ricorderai mai come farlo da una corsa all'altra, quindi finirai per reinventarlo ogni volta, o comunque per racchiuderlo in uno script.

Per una piccola cosa come questa, generalmente inizio a provare a risolverlo in 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

Fondamentalmente, questo script rimuove tutte le cifre iniziali, quindi inserisce un numero seriale crescente con spaziatura zero in primo piano, con i file numerati in base all'ordine in cui vengono passati allo script.

Lo fa in due fasi, con sertmp-prefissi per il primo passaggio per evitare qualsiasi rischio di collisioni di nomi. Se chiami questo script mp3-renamere lo chiami come:

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

ti imbatti in una collisione banale sulla prima ridenominazione se non usi 2 passaggi per fare la ridenominazione. ( 01-foo.mp3-> 01-foo.mp3.)

Se lo chiami così, però:

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

si cancella accidentalmente 01-foo.mp3la prima ridenominazione con una ridenominazione a 1 passaggio.

Se il problema si complicasse, lo riscriverei in Perl. A quel punto, potresti usare un hash per contenere la vecchia-> nuova mappatura dei nomi e usare un po 'di codice intelligente per elaborare l'ordine corretto di fare le rinominazioni al fine di evitare la necessità di 2 passaggi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.