I have several files under a directory whose names are of the form *.foo.bar. I would like to write a bash script to rename each of these files by removing the .foo part.

For example, suppose that issuing tree ~/dir/ returns

|- george.foo.bar
|- john.foo.bar
|- paul.foo.bar
|- ringo.foo.bar
|- subdir
   |- jimmy.foo.bar
   |- robert.foo

Then running script ~/foo/ should alter the contents of ~/foo to

|- george.bar
|- john.bar
|- paul.bar
|- ringo.bar
|- subdir
   |- jimmy.bar
   |- robert.foo

You can use parameter expansion mechanism

shopt -s globstar
for file in **/*foo.bar; do
    mv -v -- "$file" "$prefix$suffix"

The ${file%.foo*} removes matching suffix (leaving only prefix), and ${file#*.foo} removes prefix (leaving suffix). The double star glob (**) is needed to traverse all subdirectories and setopt -s globstar allows that glob.

  • This gives me the error line 3: setopt: command not found Aug 24 '15 at 2:46
  • @BrianFitzpatrick It should be shopt, sorry, edited the answer (setopt is from zsh).
    – jimmij
    Aug 24 '15 at 2:47
  • @BrianFitzpatrick which bash version are you using? Also if you ls **/* which files are listed?
    – jimmij
    Aug 24 '15 at 2:59
  • GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu) Aug 24 '15 at 3:00
  • Would changing **/*foo.bar to $1**/*foo.bar allow me to use my desired directory as the first argument of the script? Aug 24 '15 at 3:05

To rename all files with .foo.bar to .bar in the current directory and its subdirectories:

rename 's/\.foo\.bar/\.bar/'  * */*

Here, rename is the rename utility from the perl package. On some systems, it may be called prename.

(There is, unfortunately, also a rename executable that some systems have installed from the util-linux package. It is incompatible.)

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.