3

I have quite a number of files and directories with spaces in their filenames in my ext4 filesystems.

How should I safely find and rename them? I have bash and am running Ubuntu.

Is it possible to interactively rename each found file, i.e. be asked if I want to rename what to what for each file?

What convention for choosing filenames would you use to rename them?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Tim
  • 101,790
  • Since you ask "what convention…would you use", this suggests that having spaces is not a convention? What is the problem with spaces in filenames? (Can you not just escape/quote properly?) – Sparhawk Feb 28 '16 at 00:03
  • Spaces in filenames make find and xargs more complicated. – Tim Feb 28 '16 at 00:04
  • Yes, but this you can get around this by quoting and escaping correctly. Anyway, a partial answer is find -name '* *' -execdir sh -c 'mv -i "$1" "$(<<<$1 sed "s/ /_/g")"' _ {} \;, but the -i argument to mv isn't working in the script, so it's not interactive. I guess you could just use a more complicated read conditional. – Sparhawk Feb 28 '16 at 00:09
  • Oh I got confused. -i is only interactive if it's overwriting. Is that what you want, or do you want to be interactive in all cases? – Sparhawk Feb 28 '16 at 00:17
  • Okay, looks like DopeGhoti's answer works fine anyway. – Sparhawk Feb 28 '16 at 00:19

3 Answers3

4

Per directory, using rename is easy:

rename 's/\s/_/g' *

That will get rid of all spaces in file names in the directory and replace them with '_'. If you leave off the 'g' it would only replace the first space in the file name, so don't forget that part. * means all the files in the directory you run it in.

rename 's/\s/_/g' /home/you/something/*

Would replace all spaces in file names in the directory: /home/you/something/

This doesn't cover going through many directories, but that's how I'd do it in general.

I like underscores, that would change:

my file with spaces.txt

to

my_file_with_spaces.txt
Murphy
  • 2,649
Lizardx
  • 3,058
  • 17
  • 18
4

This script will find all files in a target directory, and generate a new script that will rename all of the files to not have spaces. You can then review the script at your leisure before execution:

#!/bin/bash
TARGET=/path/to/files
NEWSCRIPT=${HOME}/rename-spaced-files.sh

OLDIFS="${IFS}"
IFS="\n"
for file in $(find ${TARGET}/ -type f -name "* *"); do
    if [[ -f \"${file// /}\" ]]; then
        echo "# \"${file// /}\" already exists- come up with a new name for it and uncomment the next line" >> $NEWSCRIPT
        echo -n "# " >> $NEWSCRIPT
    fi
    echo "mv \"${file}\" \"${file// /}\"" >> $NEWSCRIPT

done
DopeGhoti
  • 76,081
  • 2
    It'd be great to add a -f test around the echo/mv; if the no-space version of a file already exists, emit a warning instead of an overwriting mv command. Then the user can manually rename. – Jeff Schaller Feb 28 '16 at 02:10
  • Good idea. Done- now it will put a warning and a commented-out mv in the generated script. – DopeGhoti Feb 28 '16 at 02:47
  • The following test incorrectly adds double quotes to the filename: [[ -f \"${file// /}\" ]]. Not only do the quotes not require backslash escaping, since the [[ construct performs neither field splitting nor pathname expansion, they do not need to be present at all. – Barefoot IO Feb 28 '16 at 04:10
  • Testing with http://sprunge.us/VPDG shows that you're incorrect about quotes being added to filenames. – DopeGhoti Feb 28 '16 at 17:44
2

While having spaces in filenames is totally legit in Unix and its file systems, you have to take care that you quote the names when using them with shell commands or from variables, e. g. in scripts. Else the shell will pass each word as a separate parameter to the command.

VAR="existing file with spaces in name"

#This works
ls "${VAR}"

#This results in file(s) not found
ls ${VAR}

Additionally to the answers already given, you could also use the mmv command to rename multiple files whose names match a pattern, independent from spaces in the names because with mmv you have to quote the source and target pattern anyhow.

And shamelessly quoting myself (pun not intended but merrily accepted):

Rule of thumb: Always use quotes around shell variables that contain strings when expanding them; they may contain spaces or be empty, which when unquoted often confuses the command they're passed to (too many or missing parameters).

Murphy
  • 2,649