I have a number of files in a folder, and I want to replace every space character in all file names with underscores. How can I achieve this?
11 Answers
This should do it:
for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done

- 30,738
- 21
- 105
- 131

- 5,167
- 6
- 29
- 32
-
This didn't work for me. It claimed identical files existed (with the wrong filenames). E.g. trying to rename `1 - foo.jpg` and my folder already had `1.jpg` in it. – byxor Oct 18 '17 at 14:05
-
8I find backticks bit hard to read when they are near quotes. The same but more readable would be `for file in *; do mv "$file" $(echo $file | tr ' ' '_') ; done` – Kamil S Jaron Jul 03 '18 at 08:58
-
Note: This is run from WITHIN the directory whose files' names you want to update. Alternatively, you can change `*` to `PATH_TO_YOUR_DIRECTORY`. – CFitz Mar 08 '19 at 20:06
I prefer to use the command 'rename', which takes Perl-style regexes:
rename "s/ /_/g" *
You can do a dry run with the -n flag:
rename -n "s/ /_/g" *

- 951
- 5
- 3
-
3this will work *if* you have the perl-style rename and not the simpler redhat/fedora one – David Dean Nov 27 '09 at 05:56
-
10
-
5
-
-
For some reason `rename` does not do a single thing on my CentOS box. Either with regex or not. – Buttle Butkus Jun 28 '17 at 06:32
-
Seeing this error on fish: `No matches for wildcard '*'. (Tip: empty matches are allowed in 'set', 'count', 'for'.)` – Saket Nov 12 '17 at 07:35
-
-
If your folder contains files that start with `-` you need to add `--` before the `*` – HairyFotr Oct 25 '18 at 20:42
-
1@DavidDean The rename on Arch Linux will only replace the first occurrence (not very convenient for files/directories with multiple spaces). It has the same syntax as the fedora one, so I suspect they may be the same one. But perl-rename can be installed. – prosoitos Apr 29 '19 at 14:42
Use sh...
for i in *' '*; do mv "$i" `echo $i | sed -e 's/ /_/g'`; done
If you want to try this out before pulling the trigger just change mv
to echo mv
.

- 143,651
- 25
- 248
- 329
What if you want to apply the replace task recursively? How would you do that?
Well, I just found the answer myself. Not the most elegant solution, (also tries to rename files that do not comply with the condition) but it works. (BTW, in my case I needed to rename the files with '%20', not with an underscore)
#!/bin/bash
find . -type d | while read N
do
(
cd "$N"
if test "$?" = "0"
then
for file in *; do mv "$file" ${file// /%20}; done
fi
)
done
If you use bash:
for file in *; do mv "$file" ${file// /_}; done

- 6,198
- 4
- 28
- 36
-
when i tried, i got mv: when moving multiple files, last argument must be a directory Try `mv --help' for more information. mv: when moving multiple files, last argument must be a directory Try `mv --help' for more information. – Mithun Sreedharan Nov 27 '09 at 05:32
-
Again error mv: missing file argument Try `mv --help' for more information. mv: missing file argument Try `mv --help' for more information. mv: missing file argument Try `mv --help' for more information. mv: missing file argument Try `mv --help' for more information. – Mithun Sreedharan Nov 27 '09 at 07:07
Here is another solution:
ls | awk '{printf("\"%s\"\n", $0)}' | sed 'p; s/\ /_/g' | xargs -n2 mv
- uses awk to add quotes around the name of the file
- uses sed to replace space with underscores; prints the original name with quotes(from awk); then the substituted name
- xargs takes 2 lines at a time and passes it to mv

- 49
- 1
- 5
Try something like this, assuming all of your files were .txt's:
for files in *.txt; do mv “$files” `echo $files | tr ‘ ‘ ‘_’`; done

- 30,738
- 21
- 105
- 131

- 37,814
- 16
- 84
- 124
-
2got the below error tr: two strings must be given when translating mv: missing file argument Try `mv --help' for more information. – Mithun Sreedharan Nov 27 '09 at 05:31
-
2Agin error tr: too many arguments Try `tr --help' for more information. mv: missing file argument Try `mv --help' for more information. – Mithun Sreedharan Nov 27 '09 at 07:06
Quote your variables:
for file in *; do echo mv "'$file'" "${file// /_}"; done
Remove the "echo" to do the actual rename.

- 30,738
- 21
- 105
- 131

- 327,991
- 56
- 259
- 343
-
It is echoing the mv commands prperly, but not really renaming the file! – Mithun Sreedharan Nov 27 '09 at 07:05
-
removing echo produces error like mv: cannot stat `\'1130 lake micigan view.jpg\'': No such file or directory mv: cannot stat `\'1130_1_bedroom_floor_plan.jpg\'': No such file or directory mv: cannot stat `\'1130_BedPicture_8.jpg\'': No such file or directory mv: cannot stat `\'1130_diningroom_table.jpg\'': No such file or directory – Mithun Sreedharan Nov 27 '09 at 07:08
-
Linux Linux 2.6.9-42.0.3.EL.wh1smp #1 SMP Fri Aug 14 15:48:17 MDT 2009 i686 i686 i386 GNU/Linux – Mithun Sreedharan Nov 27 '09 at 11:54
To rename all the files with a .py
extension use,
find . -iname "*.py" -type f | xargs -I% rename "s/ /_/g" "%"
Sample output,
$ find . -iname "*.py" -type f
./Sample File.py
./Sample/Sample File.py
$ find . -iname "*.py" -type f | xargs -I% rename "s/ /_/g" "%"
$ find . -iname "*.py" -type f
./Sample/Sample_File.py
./Sample_File.py

- 656
- 1
- 8
- 19
-
By far this is the only solution that worked on mac/zsh based terminal. – VanagaS Mar 17 '23 at 21:52
This will replace ' '
with '_'
in every folder and file name recursivelly in Linux with Python >= 3.5. Change path_to_your_folder
with your path.
Only list files and folders:
python -c "import glob;[print(x) for x in glob.glob('path_to_your_folder/**', recursive=True)]"
Replace ' '
with '_'
in every folder and file name
python -c "import os;import glob;[os.rename(x,x.replace(' ','_')) for x in glob.glob('path_to_your_folder/**', recursive=True)]"
With Python < 3.5, you can install glob2
pip install glob2
python -c "import os;import glob2;[os.rename(x,x.replace(' ','_')) for x in glob2.glob('path_to_your_folder/**')]"

- 1,296
- 1
- 24
- 38
The easiest way to replace a string (space character in your case) with another string in Linux
is using sed
. You can do it as follows
sed -i 's/\s/_/g' *
Hope this helps.

- 23,140
- 7
- 48
- 53