4

Say I have a folder:

/
/a.bub
/v.bub
/dr.bub
/catpictures
/catpictures/or.bub
/catpictures/on.bub

How can I format a script to change each of these to .aaa.

Here is what I've got, although it seems like a wrong approach:

find -type f -name "*.bub" -print0 -exec mv
terdon
  • 242,166
jett
  • 575

2 Answers2

11

The simplest method is using bash itself:

for f in *.bub; do mv "$f" "${f/.bub/.aaa}"; done

As very correctly pointed out by @ZeroPiraeus and @HaukeLaging this is not recursive. You can make it recursive by activating the globstar option:

shopt -s globstar
for f in **/*.bub; do mv "$f" "${f/.bub/.aaa}"; done

For older versions of bash, use find:

find -type f -name "*.bub" | while read f; do 
  mv "$f" "${f/.bub/.aaa}";
done
terdon
  • 242,166
  • Your "simplest method using bash" doesn't work recursively as per the question ... –  Jun 09 '13 at 23:33
  • That doesn't work for subdirectories. You need ** instead. In the second version the "" are missing. And sed is not necessary. bash can do that itself: mv "$f" "${f%.bub}.bub" – Hauke Laging Jun 09 '13 at 23:36
  • That doesn't work either, as written. I think you're looking for shopt -s globstar followed by for f in **/*.bub; do mv -iv "$f" "${f/.bub/.aaa}"; done (which does work to arbitrary depths of recursion, and doesn't require the *.bub you included). –  Jun 09 '13 at 23:45
  • 1
    @terdon If globstar is set then ** goes arbitrarily deep. One could say that shopt -s globstar should be added to your ** answer. – Hauke Laging Jun 09 '13 at 23:47
  • @terdon have you actually set the globstar option as mentioned by myself and @HaukeLaging in the comments above? If not, ** is the same thing as * (which would explain your result). –  Jun 09 '13 at 23:53
  • @terdon you'll still get false positives with your answer (**/*bub should be **/*.bub), and as mentioned, the preceding *.bub is redundant. –  Jun 09 '13 at 23:56
  • @ZeroPiraeus and there I go, feeling like an idiot again. Yes, I figured that out just before reading your comment. Thanks to both you and HaukeLaging. Answer edited, should work as advertised now. – terdon Jun 09 '13 at 23:56
  • @HaukeLaging thanks, everything clear now. – terdon Jun 09 '13 at 23:59
  • 1
    @terdon: the find version is a lot safer, since it won't fail on directories whose names end .bub. – rici Jun 10 '13 at 01:40
8

You could use find and xargs:

$ find some_folder -type f -name "*.bub" | 
    sed "s/\.bub$//" | 
    xargs -I% mv -iv %.bub %.aaa
`some_folder/a.bub' -> `some_folder/a.aaa'
`some_folder/v.bub' -> `some_folder/v.aaa'
`some_folder/dr.bub' -> `some_folder/dr.aaa'
`some_folder/catpictures/or.bub' -> `some_folder/catpictures/or.aaa'
`some_folder/catpictures/on.bub' -> `some_folder/catpictures/on.aaa'

... which you could generalise to a bash function:

$ extmv () {
    find "${1}" -type f -name "*.${2}" | 
    sed "s/\.${2}$//" | 
    xargs -I% mv -iv "%.${2}" "%.${3}"
}

... which you'd use like this:

$ extmv some_folder/ bub aaa