Batch rename in Bash

De Bash kent een commando “rename”. Dat is een Perl script, oorspronkelijk geschreven door Larry Wall zelf.

Omdat het Perl is, kun je er Regular Expressions in gebruiken. En dus kun je batch renames doen.

Het formaat is heel algemeen: $ rename ‘RE’ file(s)

Je mag een -n (no execute) optie gebruiken om te zien of hij doet wat je denkt dat hij gaat doen.

Augustus 2014 moest ik een zootje bestanden op volgorde converteren van .CSV naar .SQL. Die conversie doet er voor dit stukje niet toe, de volgorde wel. Natuurlijk kreeg ik ze aangeleverd als:

$ ls -l
total 10184
-rw-r--r-- 1 george users 265787 aug 24 14:02 ligger-R10-V8.csv
-rw-r--r-- 1 george users  76069 aug 24 14:02 ligger-R11-V8.csv
-rw-r--r-- 1 george users 124062 aug 24 14:02 ligger-R12-V8.csv
-rw-r--r-- 1 george users 490224 aug 24 14:03 ligger-R13-V8.csv
-rw-r--r-- 1 george users 495891 aug 24 14:03 ligger-R14-V8.csv
-rw-r--r-- 1 george users 505636 aug 24 14:04 ligger-R15-V8.csv
-rw-r--r-- 1 george users 355910 aug 24 14:04 ligger-R16-V8.csv
-rw-r--r-- 1 george users 285517 aug 24 14:04 ligger-R17-V8.csv
-rw-r--r-- 1 george users 286558 aug 24 14:05 ligger-R18-V8.csv
-rw-r--r-- 1 george users 309178 aug 24 14:05 ligger-R19-V8.csv
-rw-r--r-- 1 george users 306770 aug 24 13:59 ligger-R1-V8.csv
-rw-r--r-- 1 george users 303128 aug 24 14:05 ligger-R20-V8.csv
-rw-r--r-- 1 george users 315000 aug 24 14:05 ligger-R21-V8.csv
-rw-r--r-- 1 george users 350637 aug 24 14:06 ligger-R22-V8.csv
-rw-r--r-- 1 george users 318737 aug 24 14:06 ligger-R23-V8.csv
-rw-r--r-- 1 george users 324801 aug 24 14:07 ligger-R24-V8.csv
-rw-r--r-- 1 george users 305521 aug 24 14:07 ligger-R25-V8.csv
-rw-r--r-- 1 george users 314024 aug 24 14:07 ligger-R26-V8.csv
-rw-r--r-- 1 george users 302716 aug 24 14:08 ligger-R27-V8.csv
-rw-r--r-- 1 george users 295766 aug 24 14:08 ligger-R28-V8.csv
-rw-r--r-- 1 george users 315698 aug 24 14:08 ligger-R29-V8.csv
-rw-r--r-- 1 george users 274858 aug 24 13:59 ligger-R2-V8.csv
-rw-r--r-- 1 george users 249957 aug 24 14:08 ligger-R30-V8.csv
-rw-r--r-- 1 george users 286666 aug 24 14:00 ligger-R3-V8.csv
-rw-r--r-- 1 george users 254408 aug 24 14:00 ligger-R4-V8.csv
-rw-r--r-- 1 george users 242216 aug 24 14:00 ligger-R5-V8.csv
-rw-r--r-- 1 george users 242523 aug 24 14:01 ligger-R6-V8.csv
-rw-r--r-- 1 george users 280042 aug 24 14:01 ligger-R7-V8.csv
-rw-r--r-- 1 george users 285156 aug 24 14:01 ligger-R8-V8.csv
-rw-r--r-- 1 george users 237586 aug 24 14:02 ligger-R9-V8.csv
-rw-r--r-- 1 george users  64329 aug 24 14:09 ligger-RN1-V8.csv
-rw-r--r-- 1 george users 302521 aug 24 14:09 ligger-RN2-V8.csv
-rw-r--r-- 1 george users 288242 aug 24 14:10 ligger-RN3-V8.csv
-rw-r--r-- 1 george users 280021 aug 24 14:10 ligger-RN4-V8.csv
-rw-r--r-- 1 george users 276758 aug 24 14:10 ligger-RN5-V8.csv
$

Met andere woorden: R1 komt na R19, R2 komt na R20 en R3 tot en met R9 komen na R30. Ik had ze natuurlijk gemakkelijk zat stuk voor stuk kunnen hernoemen , maar iets dergelijks gebeurt regelmatig, dus kan het niet structureler? Ik vind dat je mensen die niet in de IT werken niet mag lastig vallen met ASCII (of tegenwoordig Unicode) sorteervolgordes. Voor gewone mensen komt negen voor tien. Kortom, ik besloot ‘even’ een RE te schrijven:

$ rename -n 's/(.*)R([123456789])-(.*)/$1R0$2-$3/' *.csv
ligger-R1-V8.csv renamed as ligger-R01-V8.csv
ligger-R2-V8.csv renamed as ligger-R02-V8.csv
ligger-R3-V8.csv renamed as ligger-R03-V8.csv
ligger-R4-V8.csv renamed as ligger-R04-V8.csv
ligger-R5-V8.csv renamed as ligger-R05-V8.csv
ligger-R6-V8.csv renamed as ligger-R06-V8.csv
ligger-R7-V8.csv renamed as ligger-R07-V8.csv
ligger-R8-V8.csv renamed as ligger-R08-V8.csv
ligger-R9-V8.csv renamed as ligger-R09-V8.csv
$

Die RE s/(.*)R([123456789])-(.*)/$1R0$2-$3/ behoeft misschien enige uitleg:

  • De eerste “s” is substitute (zoek en vervang)
  • Drie slashes: /zoekpatroon/vervangpatroon/
  • De (toevallig ook drie paar) ronde haken in het zoekpatroon kopiëren deel-patronen. Die zet ik in het vervangpatroon weer op hun plaats met $1, $2 en $3
  • In de eerste set ronde haken staat het patroon (.*): een willekeurig teken, nul of meer keer herhaald.
  • Dat eerste patroon wordt aan de achterkant begrensd door de eerste de beste “R”. Dus het zoekpatroon kopieert “ligger-“. Dat wordt met $1 in het vervangpatroon letterlijk zo teruggezet.
  • Dan volgt de letter R als begrenzing. Die zet ik in het vervangpatroon ook letterlijk weer terug.
  • Dan volgt een zoekpatroon [123456789]. Dat wil zeggen dat ik zoek naar precies één teken: een 1 of een 2, of een 3 … of een 9. Ik kopieer dat ene teken met de tweede set ronde haken  ([123456789]). Dat zet ik in het vervangpatroon terug als $2, maar wel met een 0 ervoor. Bij nader inzien had het zoekpatroon nog korter gekund: [0-9] had ook gewerkt.
  • Het tweede zoekpatroon wordt begrensd door het letterlijke teken “-“. Dat komt in het vervangpatroon ook letterlijk weer terug.
  • De derde set ronde haken  (.*) kopieert alles achter het min teken – in feite weer een willekeurig teken, nul of meer keer herhaald. Dat zet ik in het vervangpatroon terug als $3.

En daarna natuurlijk uitgevoerd zonder de -n.  Hier is de proof of the pudding:
$ rename  's/(.*)R([123456789])-(.*)/$1R0$2-$3/' *.csv
$ ls -l
total 10184
-rw-r--r-- 1 george users 306770 aug 24 13:59 ligger-R01-V8.csv
-rw-r--r-- 1 george users 274858 aug 24 13:59 ligger-R02-V8.csv
-rw-r--r-- 1 george users 286666 aug 24 14:00 ligger-R03-V8.csv
-rw-r--r-- 1 george users 254408 aug 24 14:00 ligger-R04-V8.csv
-rw-r--r-- 1 george users 242216 aug 24 14:00 ligger-R05-V8.csv
-rw-r--r-- 1 george users 242523 aug 24 14:01 ligger-R06-V8.csv
-rw-r--r-- 1 george users 280042 aug 24 14:01 ligger-R07-V8.csv
-rw-r--r-- 1 george users 285156 aug 24 14:01 ligger-R08-V8.csv
-rw-r--r-- 1 george users 237586 aug 24 14:02 ligger-R09-V8.csv
-rw-r--r-- 1 george users 265787 aug 24 14:02 ligger-R10-V8.csv
-rw-r--r-- 1 george users  76069 aug 24 14:02 ligger-R11-V8.csv
-rw-r--r-- 1 george users 124062 aug 24 14:02 ligger-R12-V8.csv
-rw-r--r-- 1 george users 490224 aug 24 14:03 ligger-R13-V8.csv
-rw-r--r-- 1 george users 495891 aug 24 14:03 ligger-R14-V8.csv
-rw-r--r-- 1 george users 505636 aug 24 14:04 ligger-R15-V8.csv
-rw-r--r-- 1 george users 355910 aug 24 14:04 ligger-R16-V8.csv
-rw-r--r-- 1 george users 285517 aug 24 14:04 ligger-R17-V8.csv
-rw-r--r-- 1 george users 286558 aug 24 14:05 ligger-R18-V8.csv
-rw-r--r-- 1 george users 309178 aug 24 14:05 ligger-R19-V8.csv
-rw-r--r-- 1 george users 303128 aug 24 14:05 ligger-R20-V8.csv
-rw-r--r-- 1 george users 315000 aug 24 14:05 ligger-R21-V8.csv
-rw-r--r-- 1 george users 350637 aug 24 14:06 ligger-R22-V8.csv
-rw-r--r-- 1 george users 318737 aug 24 14:06 ligger-R23-V8.csv
-rw-r--r-- 1 george users 324801 aug 24 14:07 ligger-R24-V8.csv
-rw-r--r-- 1 george users 305521 aug 24 14:07 ligger-R25-V8.csv
-rw-r--r-- 1 george users 314024 aug 24 14:07 ligger-R26-V8.csv
-rw-r--r-- 1 george users 302716 aug 24 14:08 ligger-R27-V8.csv
-rw-r--r-- 1 george users 295766 aug 24 14:08 ligger-R28-V8.csv
-rw-r--r-- 1 george users 315698 aug 24 14:08 ligger-R29-V8.csv
-rw-r--r-- 1 george users 249957 aug 24 14:08 ligger-R30-V8.csv
-rw-r--r-- 1 george users  64329 aug 24 14:09 ligger-RN1-V8.csv
-rw-r--r-- 1 george users 302521 aug 24 14:09 ligger-RN2-V8.csv
-rw-r--r-- 1 george users 288242 aug 24 14:10 ligger-RN3-V8.csv
-rw-r--r-- 1 george users 280021 aug 24 14:10 ligger-RN4-V8.csv
-rw-r--r-- 1 george users 276758 aug 24 14:10 ligger-RN5-V8.csv
$

Tevreden!

Er is zelfs een man page voor rename. Het wordt nog eens wat met Linux!