How to rename all files with special characters and spaces in a directory?

How can i rename all the files in a specific directory where the files contains blanks spaces and special characters ($ and @) in their names?

I tried the rename command as follows to replace all the spaces and special characters with a _:

$ ls -lrt
total 464
-rwxr-xr-x. 1 pmautoamtion pmautoamtion 471106 Jul 17 13:14 Bharti Blocked TRX Report Morning$AP@20150716.csv

$ rename -n 's/ |$|@/_/g' *
$ ls -lrt
total 464
-rwxr-xr-x. 1 pmautoamtion pmautoamtion 471106 Jul 17 13:14 Bharti Blocked TRX Report Morning$AP@20150716.csv

The command works but won’t make any changes in the file names and won’t return any error as well. How can in fix this and are there other ways as well?

Asked By: Ankit Vashistha


The -n flag is for


No Action: show what files would have been renamed.

So it’s normal if you don’t have any changes.

Regarding your command, it’s working for me:

$ touch "a @ test"
$ ls
a @ test
$ rename -n 's/ |$|@/_/g' *
a @ test renamed as a___test

Maybe depending on your shell, you have to escape the |

$ rename -n 's/ |$|@/_/g' *

Or you can use the […] notation to group characters:

$ rename -n 's/[ @$]/_/g' *
Answered By: fredtantini

Since the rename command didn’t work for me for unknown reasons and i do not get any other answers for my question, i myself tried to make an effort to make the rename possible. This might not be the best approach to rename the files but it worked for me and this is why i would like to post it as an answer so that if anyone else reads this might get some help to change the file names the way i did.

Now for me, i know that all the files will have a specific text in their names which is the word “Block”. Following are the file names before their renaming was done:

anks@anks:~/anks$ ls -lrt
total 4
-rw-r--r-- 1 anks anks   0 Jul 25 14:47 Bharti TRX Block Report$AP@12Jul15.csv
-rw-r--r-- 1 anks anks   0 Jul 25 14:47 Bharti TRX Block Report$HP@12Jul15.csv
-rw-r--r-- 1 anks anks   0 Jul 25 14:47 Bharti TRX Block Report$CH@12Jul15.csv
-rw-r--r-- 1 anks anks   0 Jul 25 14:47 Bharti TRX Block Report$KK@12Jul15.csv
-rw-r--r-- 1 anks anks   0 Jul 25 14:48 Bharti TRX Block Report$UW@12Jul15.csv

Now i have written a small shell script to make this possible. Following is the code:



# Put the old filenames in a file.
ls $PATH | grep Block >> oldValues

# Put the new names without " " or "@" or "$" in another file
cat oldValues | sed 's/$/_/g' | sed 's/@/_/g' | sed 's/ /_/g' >> newValues

# Create a new file with Old names and New names seperated by a #.
paste -d'#' oldValues newValues >> oldAndNew

# Read the file with both old and new names and rename them with the new names.
while IFS='#'; read oldValue newValue
    mv "$oldValue" "$newValue"

done < oldAndNew

rm oldValues newValues oldandNew

And that’s it, when i run the script, it renames all the file names having blank spaces () or $ or @ with _ instead of these characters.

Answered By: Ankit Vashistha

You could try like this:

for file in ./*Block*                                       
do echo mv "$file" "${file//[ ()@$]/_}"

If you’re happy with the result, remove the echo before mv to actually rename the files.

Answered By: don_crissti

I have been looking for a solution to this problem for a while now. I work on old closed systems that can’t have new packages installed. I don’t have the rename command. Finally I wrote a script that appears to work with all keyboard entered special characters. ~@#$%^&*()-_=+[]{}|;:",<.>?' The script will rename every file and directory in the current directory. It will replace all special characters,except -_. with the _ character. The outfile= line can be modified to use a different character for replacement if desired. Replace |_| with |.| to use the . character for example.


for file in ./*
  infile=`echo "${file:2}"|sed  
         -e 's|""|"\"|g' 
         -e 's| | |g' -e 's|!|!|g' 
         -e 's|@|@|g' -e 's|*|*|g' 
         -e 's|&|&|g' -e 's|]|]|g' 
         -e 's|}|}|g' -e 's|"|"|g' 
         -e 's|,|,|g' -e 's|?|?|g' 
         -e 's|=|=|g'  `
  outfile=`echo "${file:2}"|sed -e 's|[^A-Za-z0-9._-]|_|g'`
  mv "$infile" ${outfile} &

Answered By: ScriptKitty37

looking for a handsome script to remove special characters as well as german special characters, replacing them with universal ones to not remove useful information I’ve updated the last version of the script which had some minor issues resulting in:


for file in ./*
  infile=`echo "${file:2}"|sed  
         -e 's|""|"\"|g' 
         -e 's| | |g' -e 's|!|!|g' 
         -e 's|@|@|g' -e 's|*|*|g' 
         -e 's|&|&|g' -e 's|]|]|g' 
         -e 's|}|}|g' -e 's|"|"|g' 
         -e 's|,|,|g' -e 's|?|?|g' 
         -e 's|=|=|g'  `
  outfileNOSPECIALS=`echo "${file:2}"|sed -e 's|[^A-Za-z0-9._-]|_|g'`
  outfileNOoe=`echo $outfileNOSPECIALS| sed -e 's|ö|oe|g'`
  outfileNOae=`echo $outfileNOoe| sed -e 's|ä|ae|g'`
  outfileNOue=`echo $outfileNOae| sed -e 's|ü|ue|g'`
  outfileNOOE=`echo $outfileNOue| sed -e 's|Ö|OE|g'`
  outfileNOAE=`echo $outfileNOOE| sed -e 's|Ä|AE|g'`
  outfileNOUE=`echo $outfileNOAE| sed -e 's|Ü|UE|g'`
  outfileNOss=`echo $outfileNOUE| sed -e 's|ß|ss|g'`
  if [ "$infile" != "${outfile}" ]
        echo "filename changed for " $infile " in " $outfile
        mv "$infile" ${outfile}


resulting in:

enter image description here

@don_crissti: He’s doing the hokus-pokus with the infile since linux would have it’s own issues with handling special characters when moving the filename.

Answered By: Matthias R. Wiora

This one just strip the special characters from filenames

for file in *; do mv "$file" `echo $file | tr -cd '.A-Za-z0-9_-'` ; done
ॐNámásté Egész-ség.mkv --> NmstEgsz-sg.mkv

put echo after ; do to test before, like:

for file in *; do echo mv "$file" `echo $file | tr -cd '.A-Za-z0-9_-'` ; done

Another solution:

rename -v 's/[^a-zA-Z0-9.s_-]//g' *.* && rename -v 's/[s]/_/g' *.*
ॐNámásté Egész-ség.mkv --> Nmst_Egsz-sg.mkv

-n option to test before.

Answered By: eapo

For me on Ubuntu 18.04 LTS with bash 4.4.20(1)-release this one-liner worked well to remove spaces, @, : #…

To test (note the echo command:

for file in ./* ; do if [[ $file == *['!' :@#]* ]]; then echo mv "$file" "${file//[ #()@$:]/_}"; fi; done

To execute:

for file in ./* ; do if [[ $file == *['!' :@#]* ]]; then echo mv "$file" "${file//[ #()@$:]/_}"; fi; done
Answered By: Ouss

There is a very handy tool called detox that will do exactly this transformation/renaming for you.

You can pass it a directory name (eventually recursing) or a pattern of specific files:

detox ./


detox *.csv

Here is how the transformation is done on the example you gave ("Bharti Blocked TRX Report Morning$AP@20150716.csv")

ls *.csv

This package is bundle with most Linux distributions.

Answered By: Cyril Chaboisseau
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.