How to replace one char with another in all filenames of the current directories?
Solution 1
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.
Solution 2
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
Solution 3
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 ' ' _ **/*\ *
!!; !!
Solution 4
Another option would be mmv
, if installed.
mmv \*\ \* \#1_#2
Solution 5
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.
Comments
-
NobbZ over 1 year
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
-
tcoolspy over 12 yearsYou would need to use
find -maxdepth 1
to do exactly what the OP asked about operating on the current folder. -
Angel Todorov over 12 yearsUse find's
-depth
option, and you can get rid of thesort
. -
enzotib over 12 years@glenn jackman: thank you, I now understand my solution was wrong.
-
Gilles 'SO- stop being evil' over 12 years“
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 callrename
in a loop, but it's not really the right tool here.) -
Gilles 'SO- stop being evil' over 12 yearsThis only changes the first space into a
_
, it doesn't work names with multiple spaces. -
glglgl over 12 yearsOups, you are right. Sorry for the confusion.
-
kroiz over 11 yearsCould 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 (.)
-
enzotib over 11 yearsChange
-name '* *'
to-name '*_*'
and change"${1// /_}"
to"${1//_/.}"
-
kroiz over 11 yearsThanks @enzotib, I want to google for help about this
"${1// /_}"
. What is it called? -
enzotib over 11 years@kroiz: it is called "Pattern substitution". You could find it in
bash
's man page. -
Stéphane Chazelas over 10 yearsThat only works if directories don't contain spaces. (a rename of
a b/c d
toa_b/c_d
wouldn't work, you'd need first to renamea b/c d
toa b/c_d
, and thena b
toa_b
). -
Markus Pscheidt over 10 years@Stephane: Does it mean to run the same
rename
command twice? -
Stéphane Chazelas over 10 yearsWell, 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. -
JulianLai over 5 yearsWhat does the 'g' at the end of the "rename" command mean? I didn't see it in the manual.
-
JulianLai over 5 yearsHow to rename directory only? I don't want to change the filename.
-
Gilles 'SO- stop being evil' over 5 years@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. -
Abinash Dash almost 5 yearsgreat ... this helped me to rename all
_MG_blah.JPG
toIMG_blah.JPG
. -
benba over 4 years@enzotib: What's the purpose of the second bash command?
-
enzotib over 4 years@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 stringbash
appears, it is in the$0
position, and so gives a name to the script. -
benba over 4 years@enzotib: got it thanks
-
Admin almost 4 yearsWhat is
--
for in mv command? -
Gilles 'SO- stop being evil' almost 4 years@0x476f72616e So that if
$x
starts with a-
it isn't interpreted as an option. -
Matthew K. about 3 yearsTo recursively replace every space in every file name use:
find dirpath/ -depth -type f -exec rename 's/ /_/g' {} \;
where to do this to only directory names replace-type f
with-type d
while for BOTH file names and directory names, remove the-type
flag. If only replacing file names then-depth
is optional. You may need to download therename
command:sudo apt install rename
. Credit for solution: unix.stackexchange.com/a/282364/380315 -
Jeff Schaller about 3 yearsThis is really similar to an existing answer.
-
Admin almost 2 yearsrename has a
-a
parameter that tells it to replace all occurrences