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.


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

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. 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? Dec 29 '17 at 10:18
  • 9
    @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

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'

Will print:


But this code (using tabs):

cat <<- 'EOF'

Will print:


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. 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

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). Dec 30 '17 at 15:30

I came across a good example of 'space' and thought of sharing here. The following condition doesn't evaluate to true for i being somewhere between 100 and 1000.

if [ $i -ge 100 -a $i -lt 1000]; then  <some code here>  fi

Notice a missing space between 1000 and closing square bracket

But when it is changed to as mentioned below, it works as expected.

>  if [ $i -ge 100 -a $i -lt 1000 ]; then  <some code here>  fi
  • Yes, changing from no space to one or more spaces obviously matters, like e.g. cas's answer above mentions. The test [ ... ] is a regular command, so this is in principle same as cp foo bar vs. cp foobar.
    – ilkkachu
    Mar 25 '20 at 17:19
  • @ilkkachu True, But it's not so intutive in the case I mentioned and what is being mentioned for cp foo bar versus cp foobar
    – Maneesh
    Mar 25 '20 at 17:40

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.