Coder Perfect

How to use a bash script to replace spaces in file names

Problem

Can someone offer a safe way to replace spaces in file and directory names starting from a specific root directory with underscores in a recursive manner? Consider the following scenario:

$ tree
.
|-- a dir
|   `-- file with spaces.txt
`-- b dir
    |-- another file with spaces.txt
    `-- yet another file with spaces.pdf

becomes:

$ tree
.
|-- a_dir
|   `-- file_with_spaces.txt
`-- b_dir
    |-- another_file_with_spaces.txt
    `-- yet_another_file_with_spaces.pdf

Asked by armandino

Solution #1

I use:

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

It’s not recursive, but it’s quick and simple. Someone here could probably make it recursive.

The $f/ / section of the command uses bash’s parameter expansion mechanism to replace a pattern within a parameter with a string given by the user. $parameter/pattern/string is the correct syntax. See http://wiki.bash-hackers.org/syntax/pe or https://www.gnu.org/software/bash/manual/html node/Shell-Parameter-Expansion.html.

Answered by Naidim

Solution #2

Use rename (also known as prename), a Perl script that may already be installed on your system. It should be done in two steps:

find . -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'

Using the “Revision 1.5 1998/12/18 16:16:31 rmb1” version of /usr/bin/rename (a Perl script) and Jürgen’s solution, I was able to handle many levels of files and directories in a single bound:

find /tmp/ -depth -name "* *" -execdir rename 's/ /_/g' "{}" \;

Answered by Dennis Williamson

Solution #3

find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done

I initially failed to get it correctly since I didn’t consider directories.

Answered by Michael Krelin – hacker

Solution #4

Doug Harple’s cleanse can be used.

detox -r <folder>

Answered by user78274

Solution #5

A rename/find solution. rename is a util-linux command.

Because a whitespace filename can be part of a whitespace directory, you must descend depth first:

find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"

Answered by Jürgen Hötzel

Post is based on https://stackoverflow.com/questions/2709458/how-to-replace-spaces-in-file-names-using-a-bash-script