38

How do you rename all files/subdirs in the current folder?

Lets say, I have many files and subdirs that are with spaces and I want to replace all the spaces with an underscore.

File 1
File 2
File 3
Dir 1
Dir 3

should be renamed to

File_1
File_2
File_3
Dir_1
Dir_3
34

If you need to rename files in subdirectories as well, and your find supports the -execdir predicate, then you can do

find /search/path -depth -name '* *' \
    -execdir bash -c 'mv -- "$1" "${1// /_}"' bash {} \;

Thank to @glenn jackman for suggesting -depth option for find and to make me think.

Note that on some systems (including GNU/Linux ones), find may fail to find files whose name contains spaces and also sequences of bytes that don't form valid characters (typical with media files with names with non-ASCII characters encoded in a charset different from the locale's). Setting the locale to C (as in LC_ALL=C find...) would address the problem.

  • You would need to use find -maxdepth 1 to do exactly what the OP asked about operating on the current folder. – Caleb Aug 20 '11 at 6:34
  • 1
    Use find's -depth option, and you can get rid of the sort. – glenn jackman Aug 20 '11 at 14:52
  • @glenn jackman: thank you, I now understand my solution was wrong. – enzotib Aug 20 '11 at 15:19
  • 2
    Change -name '* *' to -name '*_*' and change "${1// /_}" to "${1//_/.}" – enzotib Jan 24 '13 at 19:41
  • 1
    @kroiz: it is called "Pattern substitution". You could find it in bash's man page. – enzotib Jan 30 '13 at 9:31
32

In any shell, you can loop over the files whose name contains a space. Replacing the spaces with underscores is easy in bash, ksh and zsh with the ${VARIABLE//PATTERN/REPLACEMENT} construct.

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

On Debian, Ubuntu and derivatives, you can use the Perl rename (other distributions ship a different program as rename, and that program isn't helpful here).

rename 's/ /_/g' *

An obligatory zsh solution:

autoload zmv
zmv '(*)' '${1// /_}'

An obligatory POSIX solution:

for x in *" "*; do
  y=$(printf %sa "$x" | tr " " "_")
  mv -- "$x" "${y%a}"
done
  • What does the 'g' at the end of the "rename" command mean? I didn't see it in the manual. – JulianLai Jan 15 at 8:40
  • How to rename directory only? I don't want to change the filename. – JulianLai Jan 15 at 8:44
  • @JulianLai s/…/…/g means to replace all occurrences. It's not very well explained in the manual. If you want to rename directories, there are ways, please search for it (I think I've seen it before) and if you can't find it ask a new question. – Gilles Jan 16 at 23:11
13

You can use rename for this (here assuming the one from util-linux, not the perl one):

cd /path/to/dir
rename ' ' _ *\ *

This will find all files and directories space in the name and replace the space with an underscore. Since it uses glob file matching you need to be in the right directory to start with.

If you want to do recursive matches you can, but you might have to execute the rename a couple times to catch any items in directories that themselves got renamed:

cd /path/to/dir
shopt -s globstar
rename ' ' _ **/*\ *
!!; !!
  • 2
    rename will rename the specified files by replacing the first occurrence of from in their name by to.” So this will only work for files with a single space in their name. (You could call rename in a loop, but it's not really the right tool here.) – Gilles Aug 21 '11 at 0:54
2

Another option would be mmv, if installed.

mmv \*\ \* \#1_#2
  • This only changes the first space into a _, it doesn't work names with multiple spaces. – Gilles Aug 21 '11 at 0:58
  • Oups, you are right. Sorry for the confusion. – glglgl Aug 21 '11 at 4:41
1

On Debian/Ubuntu, building upon the answers of Caleb and Gilles, this is what worked for me to rename files recursively:

cd /path/to/dir
shopt -s globstar
rename 's/ /_/g' **

Note: To preview what files would be renamed and how, use the -n switch with rename:

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

Another note: setting globstar makes ** match files in all subdirectories, so if only current directory is desired, don't set globstar or use * instead of **.

One more note: The rename command needs to be run more than once for files with multiple occurrences of the search term.

  • That only works if directories don't contain spaces. (a rename of a b/c d to a_b/c_d wouldn't work, you'd need first to rename a b/c d to a b/c_d, and then a b to a_b). – Stéphane Chazelas Dec 20 '13 at 16:15
  • @Stephane: Does it mean to run the same rename command twice? – Markus Pscheidt Dec 20 '13 at 16:19
  • Well, more like as many times as there are nested levels of directories with spaces. Ideally, you want to traverse the directory depth first, and convert only the basename of the file like in the accepted solution. Also note that bash's ** excludes dotfiles and traverses symlinks. – Stéphane Chazelas Dec 20 '13 at 16:26
0

If you're not a flash at regular expressions (I'm not!), and you can run applications designed for kde (either you use kde - k desktop or you have it's libraries installed), then krename is a great graphical utility that lets you see the before and after before you commit to the changes. It has a number of simple transformations as options and also supports regular expressions. You can even combine several sequential transformations into one rename so you don't have to design a single complex transform that does it all at once. It also has an option to continue renaming the same files after a rename has been applied.

I don't use it that often, but when I do, it really gets the job done quickly and easily. It really comes in handy when renaming various downloaded media files so you can manage them uniformly on your system. It helps to download the krename manual separately so you can refer to it while using the program.

http://www.krename.net/

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.