I need to rename files in batch--the other questions I browsed don't exactly address my problem. The names of my files are generated non-deterministically, so I can't predict what they will be named. I do know that they will start with NORMAL and end with -lib*. I'd like to replace everything in between with some string X. For example,

|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib1.concordant
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib1.deletion
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib1.divergent
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib1.inversion
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib1.translocation
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.concordant
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.deletion
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.divergent
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.insertion
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.inversion
|   |   |-- NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.translocation

So it will probably be of the form rename "s/something/X/", but I don't know what that something should be, as I don't know how to use regex.

4 Answers 4


The useful Perl powered rename isn't always available on all distros. For example, Fedora and CentOS (and presumably RedHat) use a basic rename utility that does basic search and replace and nothing much else.

If you're unfortunate enough to be using one of those, then something like the following may help:

for oldname in *; do
    newname=$(echo "$oldname" | sed -e 's/\(NORMAL\).*\(-lib.*\)/\1X\2/')
    mv "$oldname" "$newname"

If you are lucky enough to have rename available, then the following should be sufficient:

rename 's/(NORMAL).*(-lib)/$1X$2/' *

There are two unrelated programs called rename. The one found on Debian and derivatives (Ubuntu, Mint, …) is a Perl script, and its first argument is a Perl expression that transforms the old name into the new name. With that script, you can do

rename 's/.*-lib/NORMAL_X-lib/' NORMAL_*-lib*

The s operator performs a regular expression replacement. There are oodles of regular expression tutorials on the web, e.g. 1. .*-lib matches the string up to the last occurrence of -lib (.* matches any string), so s/.*-lib/NORMAL_X-lib/ replaces the NORMAL_blahblah-lib part by NORMAL_X-lib.

If you have a Linux distribution that isn't derived from Debian, then the rename utility is one that is suitable for almost no practical task. You can use a shell loop instead.

for x in NORMAL_*-lib*; do
  mv "$x" "NORMAL_X-lib${x##*-lib}"

${x##*-lib} is the value of the variable x minus the part up to the last occurrence of -lib. This is standard parameter expansion syntax.

This task is easiest in zsh, with its zmv function. Put autoload -U zmv in your .zshrc (or run it on the command line for a once-off), then run

zmv 'NORMAL_*-(lib*)' 'NORMAL_X-$1'

You could consider using lookarounds, like (?<=NORMAL).*?(?=-lib) i.e.

$ rename -v -n -- 's/(?<=NORMAL).*?(?=-lib)/X/' *
NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.insertion renamed as NORMALX-lib4.insertion
NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.inversion renamed as NORMALX-lib4.inversion
NORMAL_H_LS-A7-A0CE-10A-01D-A017-09-lib4.translation renamed as NORMALX-lib4.translation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.