15

I have a load of files(mp3, wav, txt, doc) that have been created in MS Windows and they have spaces in their names. eg The file of whoever.doc

I would like to rename them all at once, replacing the space with an underscore or dot.

4
  • Underscores or dots?
    – Jeff Schaller
    Nov 16, 2017 at 18:46
  • I would use rename or tr (no backtick on this keyboard!)
    – Joe Healey
    Nov 16, 2017 at 18:50
  • 2
    You do know it's possible to use filenames containing spaces in the UNIX/Linux world, don't you...? Nov 16, 2017 at 21:00
  • 1
    If any of the answers solved your problem, please accept it by clicking the checkmark next to it. Thank you!
    – Jeff Schaller
    Nov 19, 2017 at 14:49

7 Answers 7

30

The shell can do this pretty easily (here assuming ksh93, zsh, bash, mksh, yash or (some builds of) busybox sh for the ${var//pattern/replacement} operator):

for file in *.doc *.mp3 *.wav *.txt
do
  mv -- "$file" "${file// /_}"
done

Change the *.doc ... glob to match whatever files you're interested in renaming.

To rename all of the files in the current directory that currently have spaces in their filenames:

for file in *' '*
do
  mv -- "$file" "${file// /_}"
done

You might also consider adding a "clobber" check:

for file in *' '*
do
  if [ -e "${file// /_}" ]
  then
    printf >&2 '%s\n' "Warning, skipping $file as the renamed version already exists"
    continue
  fi

  mv -- "$file" "${file// /_}"
done

Or use mv's -i option to prompt the user before overriding a file.

2
  • is there a way to include all file types and folders as well? at the moment i am adding/removing the file extensions, but i cannot get all of them and i cannot have the folders. Also some of them have a slash. is it possible to make it as underscore?
    – john
    Nov 29, 2017 at 18:08
  • @john, see my recent edit; for recursively renaming files & folders, you'll want to look for (or ask) a question that focuses on a 'find' based solution, as you don't want to rename folders before catching the files inside of them. Unix files cannot contain (forward) slashes, so either it's a backslash, or something that looks like a slash but isn't actually, or you're wanting to move files in subdirectories up a level and renaming them to include the old directory name with an underscore. All good material for a separate question.
    – Jeff Schaller
    Nov 29, 2017 at 19:40
6

Aside from what's been mentioned, the program detox might be of some interest. It's designed specifically for doing this type of thing, and handles lots of stuff other than just spaces. Provided you don't have any diacritical marks, parentheses, or other odd stuff in the filenames, the following should do exactly what you want if run at the top of the directory tree:

detox -r .

Note that that will also fix the names of directories, so do not run that on the Users directory from a Windows system, otherwise you're liable to break things (Windows requires specific names for certain folders in the user directories, and this will change those folders' names).

1
  • Worked for me! Detox is in Debian, so sudo apt install detox was all it took to get started. Jul 17, 2022 at 10:12
4

You can use sed, e.g.:

mv -i "${original_file}" "$(echo "${original_file}" | sed 's/ /_/g')"

Here's an example.

Create a file with spaces in its name:

touch "/tmp/test file with spaces"

Rename the file:

mv -i \
"/tmp/test file with spaces" \
"$(echo "/tmp/test file with spaces" | sed 's/ /_/g')"

Here is the new name of the file:

test_file_with_spaces

You could do the same thing with tr instead, i.e.:

mv -i "${original_file}" "$(echo "${original_file}" | tr ' ' _)"

Or using Bash substring replacement:

mv -i "${original_file}" "${original_file// /_}"

Or using the rename command:

rename "s/ /_/g" "${original_file}"
3
rename s/\ /_/ *

I can’t remember right now whether the white space needs escaping or not with rename.

(Or swap * for whatever extension.)

4
  • 2
    Only when you don't quote the substitution pattern. If recommend rename 's/ /_/g' * myself. Or even rename 'y/ /_/' * Apr 3, 2019 at 17:54
  • 2
    This works, but only for the first occurring space in each filename.
    – rubo77
    Sep 29, 2019 at 18:00
  • 1
    Regexp doesn't seem to work with util-linux's rename.
    – Geremia
    Apr 11, 2020 at 19:56
  • 1
    @rubo77 Append g to the end of the string. This is what worked for me: rename 's/\ /_/g' *
    – ali14
    May 1, 2022 at 17:58
1

The correct answer is given above by Austin Hemmelgarn, use:

    detox -r .

Before running the detox command preview changes to be made with the option -n like this:

    detox -n -r .

Running the detox command from the home directory as the starting-point, and excluding all hidden files and directories, and excluding particular directories such as a timeshift directory for example, use the form:

find ~ -path '*/\.*' -prune -o -path */timeshift/* -prune -o -exec detox -n {} \;

To actually run the above command remove the -n

0

Replace all spaces with underscores in mp3, txt, wav, and doc filenames using qmv and vim:

qmv -f do --editor="vim -c '%s/ /_/g' -c 'wq'" \
    *.mp3 *.txt *.wav *.doc

qmv is a part of renameutils.

-1

if rename s/\ /_/ * not work use rename -v ' ' '_' *

1
  • 2
    Could you explain why? Also, the user only wants to rename certain files.
    – Kusalananda
    Sep 4, 2019 at 7:20

You must log in to answer this question.

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