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


9 Answers 9


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// /_}"

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// /_}'


autoload zmv
zmv '*' '${f// /_}'

An obligatory POSIX solution:

for x in *" "*; do
  y=$(printf %s/ "$x" | tr " " "_")
  mv -- "$x" "${y%/}"
  • What does the 'g' at the end of the "rename" command mean? I didn't see it in the manual.
    – JulianLai
    Jan 15, 2019 at 8:40
  • How to rename directory only? I don't want to change the filename.
    – JulianLai
    Jan 15, 2019 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. Jan 16, 2019 at 23:11
  • 1
    What is -- for in mv command?
    – user124983
    May 23, 2020 at 15:47
  • 1
    @0x476f72616e So that if $x starts with a - it isn't interpreted as an option. May 23, 2020 at 17:39

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.

  • 1
    Use find's -depth option, and you can get rid of the sort. Aug 20, 2011 at 14:52
  • 1
    Could some one please elaborate on what should be change so this could be used to replace other characters. For example I could not make it work for replacing _ with a period (.)
    – kroiz
    Jan 24, 2013 at 10:34
  • 3
    Change -name '* *' to -name '*_*' and change "${1// /_}" to "${1//_/.}"
    – enzotib
    Jan 24, 2013 at 19:41
  • 1
    @kroiz: it is called "Pattern substitution". You could find it in bash's man page.
    – enzotib
    Jan 30, 2013 at 9:31
  • 1
    @benba: it is not a second bash command, you should interpret it as: bash -c script-string $0 $1 $2 etc, so the second time the string bash appears, it is in the $0 position, and so gives a name to the script.
    – enzotib
    Jan 7, 2020 at 12:19

You can use rename for this (here assuming the one from util-linux, not the perl one, and not the removed 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 ' ' _ **/*\ *
!!; !!
  • 4
    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.) Aug 21, 2011 at 0:54
  • 3
    rename has a -a parameter that tells it to replace all occurrences
    – NeuroXc
    Jul 12, 2022 at 17:04
  • That globstar approach won't work. You'd need to process the files depth-first (which bash contrary to zsh can't do) and transform the base names only. You're also missing some --s Jun 26, 2023 at 8:10

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. Aug 21, 2011 at 0:58
  • Oups, you are right. Sorry for the confusion.
    – glglgl
    Aug 21, 2011 at 4:41

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). Dec 20, 2013 at 16:15
  • @Stephane: Does it mean to run the same rename command twice? Dec 20, 2013 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. Dec 20, 2013 at 16:26

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.



Suppose you have only the traditional rename command installed (the one that comes with Slackware).

And you have those files:

"File 1 another space"
"File 2 with other space"
"Dir 1 also"
"Dir 2 and so on"
  • If you issue:

     rename -v ' ' _ "File 1 another space"

you get:

"File_1 another space"
  • If you issue:

     F=$(ls -1 File_1*) ; while [[ "$F" =~ " " ]] ; do rename -v " " _ $F ; sleep 1 ; F=$(ls -1 File_1*) ; done

You will get

  • Then the complete solution would use two loops such as:

    for F in * ; do \
      while [[ "$F" =~ " " ]] ; do \
        G=$(rename -v " " _ "$F" | cut -d '`' -f3) ; \
        F="${G::-1}" ; \
        echo $F ; \
        sleep 1 ; \
      done ; 

The traditional rename command only changes the first character found that match the pattern.

Because of the echo command above (optional, you may want to remove them, as well as the sleep), you will get the following output:

Dir_1 also
Dir_2 and so on
Dir_2_and so on
Dir_2_and_so on
File_1 another space
File_1_another space
File_2 with other space
File_2_with other space
File_2_with_other space
  • Not sure why you'd call that dumb rename implementation from util-linux traditional. It is Linux-specific and was added to util-linux 2.10e circa 2000 over a decade after the rename from perl which was added in perl 3 from 1989 (predates even Linux). Nov 25, 2022 at 12:49
  • Call it whatever you like. Just remember to be a nice boy while you are at it. Peace.
    – DrBeco
    Nov 25, 2022 at 22:19

Use detox command.

In your case use simply:

detox -v .
  • This one stubbornly appends _ after characters it deaccents. No way around it, "łódź" will become "l_o_dz_" instead of "lodz". Apr 25 at 15:36
for f in *\ *; do mv "$f" "${f// /}"; done

(Given that you are in the directory where you want to do this operation).


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .