13

I have been told that the spaces are important in bash or other shell scripts and I should not change the existence of spaces unless I know what I am doing. By "changing the existence" I mean either inserting a space between two non-space characters or removing a space between two non-space characters, e.g. changing var="$val" to var ="$val" or vice versa. I want to ask

Are there any cases in which using a single space or using multiple consecutive spaces in a shell script makes a difference?.

(Of course, inserting/deleting a space in quotes makes a difference ,like changing from echo "a b" to echo "a b" or vice versa. I am looking for examples other than this trivial example.)

I have come across this question but that one is about adding and removing spaces between two non-space characters for which I know many examples that it would make a difference.

Any help would be appreciated. Include more varieties of shells if possible.

18

Outside of quotes, the shell uses whitespace (spaces, tabs, newline, carriage-return, etc) as a word/token separator. That means:

  • Things not separated by whitespace are considered to be one "word".
  • Things separated by one-or-more whitespace characters are considered to be two (or more) words.

The actual number of whitespace chars between each "thing" doesn't matter, as long as there is at least one.

  • Thank you. I can't find any counter example myself. I just want to make sure. – Weijun Zhou Dec 29 '17 at 2:55
  • 2
    Bash also considers form feeds and vertical tabs to be whitespace. – fpmurphy Dec 29 '17 at 4:08
  • true. i originally wrote '...newlines, etc' and then changed it to explicitly add carriage-returns. accidentally dropped the 'etc'. – cas Dec 29 '17 at 5:03
  • What if the number of spaces is so large, that the program cannot fit into memory? – Worse_Username Dec 29 '17 at 10:18
  • 7
    @Worse_Username The whitespace does not have to fit in memory. I just created a 48GB script on a machine with 8GB of RAM and 20GB of swap. It ran just fine. It did take 3 minutes to crunch through all of that whitespace, but in the end it successfully ran an echo command with that much whitespace between the command and the argument. – kasperd Dec 29 '17 at 11:59
23

This is probably cheating, but this:

rm foo\ bar         # "delete the file named 'foo bar'"

is different from this:

rm foo\  bar        # "delete the files named 'foo ' and 'bar'"

even though the spaces are not in quotes. ;-)

More confoundingly, this:

rm \
    foo          # "delete the file named 'foo'"

is different from this:

rm \ 
    foo          # "delete the file named ' ', then run the command 'foo'"

even though they look identical!

  • Even though the spaces are not in quotes, the backslash is functionally similar to form of quoting and I'd put this in the same category as the question's "trivial example". (It is interesting though.) – David Z Dec 29 '17 at 23:22
12

If we don't talk about the space character (U+0020), but any whitespace character (U+0020, \n, \t, etc.), then one particular case come to my mind: Here-Documents.

This code (using spaces):

cat <<- 'EOF'
<space><space>foo
EOF

Will print:

  foo

But this code (using tabs):

cat <<- 'EOF'
<tab><tab>foo
EOF

Will print:

foo

That's because (as POSIX states):

If the redirection operator is <<-, all leading <tab> characters shall be stripped from input lines and the line containing the trailing delimiter.

  • 1
    That is interesting. I thought about here-documents but did not know the <<- operator. Thank you very much. – Weijun Zhou Dec 29 '17 at 3:48
  • here documents are a form of quoted text, not shell code. shell word-splitting doesn't apply. – cas Dec 29 '17 at 5:07
2

It also has an effect when writing assignment statements. Like if I say FOO=xyz it will create an environment variable named FOO with value xyz, but if I separate the equals with a space, it will think that I'm invoking a program named FOO with the arg =xyz. So it does matter when it comes to certain syntax.

  • Usually FOO=xyz does create an internal shell variable but not an environment variable. You need set -a or export FOO=xyz for that (i.e. making it part of the environment of non-subshell subprocesses). – Hauke Laging Dec 30 '17 at 15:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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