How to rename file names - replacing underscores with spaces - in a shell command line script

I am trying to rename all files in a folder replacing underscores with spaces.

i.e. this_is_a_test --> this is a test

but somehow I'm messing up the quoting

> for file in * ; do echo mv -v $file $(echo $file | sed 's/_/\\ /g') ; done
mv -v this_is_a_test this\ is\ a\ test

that looks OK, but if I remove the 'echo' mv complains as if the backslashes were removed

> for file in * ; do mv -v $file $(echo $file | sed 's/_/\\ /g') ; done
mv: target ‘test’ is not a directory

Can someone point out the error of my ways?


Using rename:

rename -n 's/_/ /g' *

If everything is ok, remove the -n switch:

rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file_1
├── file_2
├── file_3
└── file_with_underscores

0 directories, 5 files
~/tmp$ rename 's/_/ /g' *
~/tmp$ tree
.
├── file
├── file 1
├── file 2
├── file 3
└── file with underscores

0 directories, 5 files

There is a minor mistake. Use "$newfile" instead of only $newfile. You need to use "

Here is the correct one.

for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/\\ /g')" ; done

If you have filename this_is_a_test it will rename file to this\ is\ a\ test.

In case if you want to rename the file to this is a test. Use the code below,

for file in * ; do mv -v "$file" "$(echo $file | sed 's/_/ /g')" ; done

It is a good practise to use variables inside "" while you writing good shell script.


Instead of mv -v "$file" "$(echo $file | sed 's/_/\\ /g')" you can use a much simpler command mv "$f" "${f//_/ }".

To add it in your script:

for f in * ; do mv "$f" "${f//_/ }" ; done

And that's it.


Use the find and rename command:

find <your_start_folder> -type f -regex ".*_+.*" -exec rename 's/_/ /g' {}  \;

This command renames all file with a _ in the filename recursively.

Explanation

  • -regex ".*_+.*"

    Find all files with at least one _ in the filename

  • _

    Replace all occurrences of _

  • … with a space character ( )


Example

% ls -Rog
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:39 foo
-rw-rw-r-- 1    0 Jun 15 17:34 foo_bar

./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo_bar

% find . -type f -regex ".*_+.*" -exec rename 's/_/ /g' {} \;

% ls -Rog                                                                 
.:
total 4
drwxrwxr-x 2 4096 Jun 15 17:40 foo
-rw-rw-r-- 1    0 Jun 15 17:34 foo bar

./foo:
total 0
-rw-rw-r-- 1 0 Jun 15 17:32 foo bar