I have this command to go through all my files in my Music directory, and all subdirectories, and replace any square brackets in the file name with rounded brackets:

find /home/Music/ -depth -name "* *" -execdir rename 's/\[/\(/g' "{}" \;

But it doesn't work. It doesn't return any errors, it just doesn't make the replacements.

I thought I properly escaped the characters. Where am I going wrong?

Also, eventually I"ll want to replace curly brackets, {}, with rounded brackets , (), as well. Just thought I'd mention that now in case curly brackets came with yet more complications.

  • 1
    This should work as long as you have files with spaces in their names. What *nix are you on?
    – terdon
    Apr 7 '13 at 4:11
  • Would you mind showing some sample directory data in this question?
    – slm
    Apr 7 '13 at 4:36
  • Try adding -v (and optionally -n) to the rename part to see what is it doing. Also, you might need to modify the s/// option to be s///g to replace all matched characters, not only the first one it encounters.
    – zorlem
    Apr 7 '13 at 11:27
  • rename is not a standard tool, so the various implementations have different syntax. Have you checked that you use the right syntax?
    – manatwork
    Apr 7 '13 at 11:29
  • @terdon: That was my mistake. I totally forgot "* *" would look for files with spaces in the name, whereas what I need to do is "*[*". If you convert your comment to an answer I'll mark you correct.
    – Questioner
    Apr 7 '13 at 15:23

The only reason I can see why it wouldn't work is if there are no files with spaces in their names. The pattern "* *" will only match if the filename has a space.

If you want to find files whose name contains square brackets, do

find /home/Music/ -depth -name "*[*" -execdir rename 's/\[/\(/g' "{}" \;
  • -name '*\[*' or -name '*[[]*' would be more portable. Apr 7 '13 at 19:19

There are two main rename implementations on Linux:

  • The one that comes with perl (which is probably the one you were expecting)
  • The one that comes with util-linux (probably the one you have).

The syntax for the one that comes with util-linux would be:

find ... -execdir rename '[' '(' {} +

However, that would only replace one occurrence of [.

perl's rename might be called prename on your system.

An alternative to rename is zsh's zmv. It would take care of descending directories depth first and avoid problems with collisions.

In zsh:

autoload zmv
zmv '(**/)(* *)' '$1${2//\[/(}'

And for converting both {} and [] to ():

zmv -n '(**/)(* *)' '$1${${2//[]\}]/)}//[[{]/(}'    

The following should work:

for i in `find o -type f`; do new="${i/\[/(}" ; if [ "${i}" != "${new}" ]; then mv ${i} ${new} ; echo "Moving ${i} to ${new}"; fi ; done

If the file names contain spaces, try the following:

OLDIFS=${IFS} ; IFS=$(echo -en "\n\b") ; for i in `find o -type f`; do new="${i/\[/(}" ; if [ "${i}" != "${new}" ]; then mv ${i} ${new} ; echo "Moving ${i} to ${new}"; fi ; done; IFS=${OLDIFS}
  • You're using command substitution without setting IFS (though the OP was explicitly wanting to rename files with spaces in their name) ${i/../} is to replace one occurrence while the OP used the g flag, you forgot to quote some variables. That won't work properly if directory names contain [ Apr 7 '13 at 15:04
  • Modified answer to handle spaces.
    – devnull
    Apr 8 '13 at 7:41

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.