0

There is an answer from SuperUser, which renames filenames containing whitespace:

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

The part I don't understand is *\ *.

The author wrote that:

*\ * selects all files with a space in their name as input for the the for loop. The pattern X selects all files with X in their name, and for the special character space, we have to escape it with a slash so that bash doesn't treat it as separating different arguments.

Since * does not match a space, why does *\ * also match files with multiple space character when it only has one space in it?

1
  • 6
    * does match spaces. Why do you think it doesn't?
    – muru
    Commented Apr 22 at 13:48

2 Answers 2

8

There are two parts to the globbing pattern *\ *.

  1. An asterisk matches zero or more characters
  2. A backslash escapes the following character so that it's not treated specially in any way by the shell. (It's the same as quoting it.)

You could also write *\ * as *' '* or even *" "*, and in any case the space is treated just like any printable character rather than the token separator it otherwise is in the syntax of the shell.

Note also, in response to a confusion in your question, that * can match a space just as happily as any other character (or set of characters). The pattern *\ * matches anything, then a space, then anything, so it guarantees there must be at least one space in file names that match.

Finally, file names having spaces in them are not a problem provided your code is well written. For example, this will process any file name regardless* of the characters it contains:

for f in *; do printf '>> %s <<\n' "$f"; done    # ‡

* Actually if you're in a Unicode locale you may hit problems with some byte sequences that do not correspond to valid Unicode characters. You can get around that by setting LC_CTYPE=C

‡ It's easier to printf '>> %s<<\n' * but that wouldn't illustrate the point I wanted to make

3

This is because * matches any string, including strings with spaces.

Instead of a space, let's use X. Suppose we have all these files in the current directory:

  • abc
  • X
  • defg
  • hijk
  • lmXXnop
  • qXrsXt
  • uvwXX

(You can make them by running touch abc X defg hijk lmXXnop qXrsXt uvwXX.)

Now the globbing pattern * matches all of them:

bash-3.2$ echo *
X abc defg hijk lmXXnop qXrsXt uvwXX

If I add an X, the pattern means "anything ending in an X":

bash-3.2$ echo *X
X uvwXX

(Note that this includes uvwXX, which has two Xs. This is because * matches uvwX.)

If I add another X, the pattern means "anything ending in two X's":

bash-3.2$ echo *XX
uvwXX

But if I instead add another *, the pattern means "anything containing at least one X":

bash-3.2$ echo *X*
X lmXXnop qXrsXt uvwXX
1
  • I think the OP hasn't understood that \ means "a regular space character".
    – terdon
    Commented Apr 22 at 15:19

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.