How to replace one char with another in all filenames of the current directories?
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
File_1 File_2 File_3 Dir_1 Dir_3
8 Answers 8
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 $ construct.
for x in *" "*; do mv -- "$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).
An obligatory zsh solution:
An obligatory POSIX solution:
for x in *" "*; do y=$(printf %s/ "$x" | tr " " "_") mv -- "$x" "$" done
@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.
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" "$"' 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.
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 (.)
@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.
You can use rename for this (here assuming the one from util-linux , not the perl one, and not the removed one):
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 ' ' _ **/*\ * !!; !!
“ 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.)
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
Another option would be mmv , if installed.
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 :
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 ).
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.
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).
"File 1 another space" "File 2 with other space" "Dir 1 also" "Dir 2 and so on"
rename -v ' ' _ "File 1 another space"
F=$(ls -1 File_1*) ; while [[ "$F" =~ " " ]] ; do rename -v " " _ $F ; sleep 1 ; F=$(ls -1 File_1*) ; done
for F in * ; do \ while [[ "$F" =~ " " ]] ; do \ G=$(rename -v " " _ "$F" | cut -d '`' -f3) ; \ F="$" ; \ echo $F ; \ sleep 1 ; \ done ; 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_1_also Dir_2 and so on Dir_2_and so on Dir_2_and_so on Dir_2_and_so_on File_1 another space File_1_another space File_1_another_space File_2 with other space File_2_with other space File_2_with_other space File_2_with_other_space
Linux — Replacing spaces in the file names
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 11
for file in *; do mv "$file" `echo $file | tr ' ' '_'` ; done
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.
I 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
Note: This is run from WITHIN the directory whose files’ names you want to update. Alternatively, you can change * to PATH_TO_YOUR_DIRECTORY .
I prefer to use the command ‘rename’, which takes Perl-style regexes:
You can do a dry run with the -n flag:
@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.
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 .
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" $; done fi ) done
How to replace a string in all folder and file names [duplicate]
How can I recursively replace a string in all folders and files’ name with a different string? I am running Red Hat 6 and I can find them with:
find . -type f -exec sed -i 's/string1/string2/g' <> +
how can I replace a string with the mv command? There might be different folders names containing that string. I would need something like «find . -type f -exec sed -i ‘s/string1/string2/g’ <> +» but for folder names
The command you show ( sed ) doesn’t change any file names. It replaces the string inside the file but leaves the file name as it was.
3 Answers 3
find . -type f -exec rename 's/string1/string2/g' <> +
The find . -type f part of the command means to search for all files ( -type f ) in the current directory ( . ).
- The -exec option tells find to execute a command on each file it finds.
- The rename command is used to rename files, and the syntax used here is for the Perl version of rename .
- The ‘s/string1/string2/g’ is a regular expression that specifies what to search for and what to replace it with. In this case, string1 is the string to be replaced, and string2 is the replacement string. The /g at the end means to replace all occurrences of string1 in the filename.
- The <> symbol is a placeholder for the filename that find has found.
- The + at the end of the command tells find to pass multiple filenames at once to the rename command, which is more efficient than invoking rename for each individual file.
So, overall, this command searches for all files in the current directory and executes the rename command to replace all occurrences of string1 with string2 in the filename for each file found.
Change Names of Multiple Files Linux
I have a number of files with names a1.txt, b1.txt, c1,txt. on ubuntu machine. Is there any quick way to change all file names to a2.txt, b2.txt, c2.txt. In particular, I’d like to replace part of the name string. For instance, every file name contains a string called «apple» and I want to replace «apple» with «pear» in all file names. Any command or script?
6 Answers 6
without any extra software you can:
for FILE in *1.txt; do mv "$FILE" $(echo "$FILE" | sed 's/1/2/'); done
for f in 1.txt; do echo "$f" "$"; done
replace ‘echo’ with ‘mv’ if the output looks correct.
and I want to replace «apple» with «linux»
for f in *apple*; do mv "$f" "$"; done
The curly brackets in line 1 should work with bash at least.
Well, first, I figured replacing linux with pear would be the more obvious fix as «apple»->»pear» is the example in the OP and pear was clearly the intent while linux was a copy/paste remnant. Second, your second command needs done affixed to the end otherwise it prompts for it. Third, while the curly braces do work, I find the * wildcard operator to be more widely applicable (which is the point on SO) and also more intuitive. (This third point is more of an opinion and you do use * in your second example, so I would be ok if you left your first command as is.)
Your idea to echo the files first to make sure of correct output before the actual action (Linux can be quite unforgiving of small typos/mistakes) makes this answer a bit better than the accepted I feel, but I don’t feel that I can support it unless it 1: does the same thing it claims to do (the linux/pear mix-up in your original answer) and 2: works immediately when copy/pasted as a command (which it requires the done to do)
@River: