How do I rename files with spaces using the Linux shell?

29

4

I named a number of files with spaces in them, and I want to replace the space with _. However, every time I write a command in the shell with the file name (eg Spring 2011), the shell doesn't recognize the file or directory.

What can I do about this? Is there any way to use the unicode character for a space?

Phil Braun

Posted 2011-06-08T19:38:59.730

Reputation: 421

for programmatically renaming N files, use a bash for loop: see my solution here.

– Trevor Boyd Smith – 2018-10-03T17:53:04.077

Answers

35

Escape the space, e.g. Spring\ 2011, or use quotes, e.g. 'Spring 2011'. In the future, it's typically a bad idea to use file names with spaces in them on any *NIX.

If you've got rename, you can use this:

rename ' ' '_' [filenames...]

Rafe Kettler

Posted 2011-06-08T19:38:59.730

Reputation: 1 107

Didn't work for me (Ubuntu/LinuxMint).

This did work: rename "s/\s/_/g" [filenames...] – Nissim Nanach – 2016-08-25T23:06:41.607

for programmatically renaming N files, use a bash for loop: see my solution here.

– Trevor Boyd Smith – 2018-10-03T17:55:09.377

1this only did the first space for me... which is not helpful (i have rename version 2.23) – Trevor Boyd Smith – 2018-10-05T14:13:27.460

1Do you know is there anyway to do this for all the files at once? – None – 2011-06-08T19:55:48.967

@phil for the rename command, specify a pattern for filenames that matches all the files you want to rename (e.g. if there's a common prefix/suffix). – Rafe Kettler – 2011-06-08T20:04:41.087

3Why is it a bad idea? It's the responsibility of the programmer to handle filenames properly. – glenn jackman – 2011-06-09T14:28:18.797

@glenn because spaces in a filename have to be either escaped or quoted in the shell, which is extra effort for anyone writing scripts and can be error prone. – Rafe Kettler – 2011-06-09T15:16:10.430

1@rafe, really it's error prone not to handle filenames properly up front. The extra effort comes when having to debug a script when you simply forgot to quote variables containing a filename. – glenn jackman – 2011-06-09T15:52:12.580

3This answer does not seem to work (on Ubuntu 12.04 LTS, at least). The answer from unutbu works fine though. – DNA – 2012-09-03T14:44:40.813

32

If your machine has the rename command, then this will change all spaces to underscores in all files/dirs in the current working directory:

rename 's/ /_/g' *

unutbu

Posted 2011-06-08T19:38:59.730

Reputation: 555

2Confirmed to work in Ubuntu 12.04 – anthonygore – 2014-10-10T06:50:03.367

1didn't work for me... i got an error of "rename: not enough arguments". i have version rename --version rename from util-linux 2.23.2. – Trevor Boyd Smith – 2018-10-05T14:12:48.373

-bash: /usr/bin/rename: Argument list too long – nmz787 – 2019-12-08T10:04:47.673

24

If you don't have rename or prefer to use just the shell:

for f in *\ *; do mv "$f" "${f// /_}"; done

Broken down:

  • *\ * selects all files with a space in their name as input for the the for loop.
  • The quotes around "$f" are important because we know there's a space in the filename and otherwise it would appear as 2+ arguments to mv.
  • ${f//str/new_str} is a bash-specific string substitution feature. All instances of str are replaced with new_str.

blahdiblah

Posted 2011-06-08T19:38:59.730

Reputation: 3 125

2this works but for me it only replaces the first space. if i use for f in *\ *; do mv "$f" "${f// /_}"; done it works – billynoah – 2014-07-07T21:52:20.770

@billynoah Good catch, updated. – blahdiblah – 2014-07-07T22:05:37.390

@blahdiblah Thank you so much! You just saved me so much time! – Guerrilla – 2016-02-20T17:03:08.463

@blahdiblah your solution is way way more elegant than my solution. good job. I didn't think the for loop glob would work... so i did the glob outside of the for loop.

– Trevor Boyd Smith – 2018-10-03T17:58:45.457

3

mv "Spring 2011.file" Spring_2011.file should tell the command-line to take the quoted string as a single input.

rockerest

Posted 2011-06-08T19:38:59.730

Reputation: 153

This is the only answer that I could get to work. – blakeoft – 2015-01-20T22:00:14.580

1

To programmatically rename N files, you can use a simple bash for loop.

#!/bin/bash

set -eux

# find all your files by using a `grep` pattern
pattern="insert_filename_pattern_here" # you must enter your filename pattern here

# create an array of filenames and split on newlines
IFS=$'\n'
tmp=($(ls | grep ${pattern}))
unset IFS

# for each filename
for filename in "${tmp[@]}"; do
    # rename the filename to use "_" character instead of a " " character
    mv -v "${filename}" "${filename// /_}"
done

If you have less than 5 filenames, then you can manually type in all the filenames and use the rename command like the above solution suggests. But for me... I prefer the programmatic solution... even when there is only 4 files.

p.s.

if you aren't familiar with Bash's Parameter Expansion (i.e. ${filename// /_}) you could use the rename command:

if ((0)); then
    mv -v "${filename}" "${filename// /_}"
else
    rename ' ' '_' "${filename}"
fi

Trevor Boyd Smith

Posted 2011-06-08T19:38:59.730

Reputation: 2 093