0

Naidim answered this question: How to replace spaces in file names using a bash script

This was the only answer I could get to work for me, but I don't understand what I am looking at.

for f in *\ *; do mv "$f" "${f// /_}"; done
  1. I didn't know the for loop would just search through all the files with this basic syntax.
  2. I see the mv statement, but what is that command expansion?

3 Answers 3

5

Breaking it down:

  • *\ * is a filename glob pattern. This expands to all the files in the current directory that have spaces in them. Normally spaces separate arguments to commands (which happens before glob expansion), but having a \ escape before it makes it a literal space and thus part of the glob pattern.

  • for f in *\ *; is a for loop, looping over all the things after in -- in this case the list of files from the glob expansion. The variable f will be set to each filename in turn and the code up to the done command will be executed for each filename.

  • "$f" is a variable expansion. Variable expansion comes before word splitting (unlike glob expansion), so the quotes are necessary to keep the spaces in the filename togther as part of a single argument and not split into multiple arguments.

  • ${f// /_} is a variable expansion with substitution. The initial // means the pattern is applied repeated to the variable contents, not just once. The space between the / / is the pattern to search for, and the final _ is the replacement, so all spaces in f (the filename from the loop) will be replaced with underscores.

1
  • Wow, thank you! A few of us at work were trying to break this down, but had never seen the command like this.
    – Ambrose
    Commented Jun 2, 2017 at 19:32
1

You may want to read more about globbing and Bash parameter expansion to understand this code.

  • *\ * => is the glob which matches all entries in the current directory that have one more spaces in them
  • ${f// /_} => Bash parameter expansion that replaces spaces with a - in the variable f (1:1 replacement)

So, the loop picks up all entries in current directory (files, directories, symlinks, etc.) that have a space in their name and renames them to a name that uses _ in place of spaces.

0

The confusing expansion is a parameter substitution. The form ${foo/bar/baz} is used to search for the string bar inside $foo and replace it with baz. If bar starts with a / (as is the case in your loop), then all occurrences of bar are replaced with baz. For more information you can read the Parameter Expansion heading in the bash manpage.

Not the answer you're looking for? Browse other questions tagged or ask your own question.