I have worked all my life in HPUX/ksh shell, so bash these days seems to be throwing new ways of doing many things (many of which don't seem to be POSIX compliant - for example 'mkdir -p /root/{abc,def,ghi,jkl}' - apparently this is a coding guideline best-practice in bash / OpenStack - but that's a different rant altogether).

Anyways, I have been seeing this sort of script execution in multiple places in OpenStack code:

ENABLE_VCENTER=true bash /root/stack_install.sh

Can someone explain how this works - I know that the shell will set the variable and then invoke the shell script (which is the explanation the classic nooB mistake for why variable assignment shouldn't be with spaces - eg. HELLO= world). But what exactly happens internally?

Also, why doesn't it seem to work for me when I try this command:

HELLO=world echo $HELLO

I get the following output from the shell:

[ ubuntuOne : /home/bumblebee ]
> HELLO=world echo $HELLO

[ ubuntuOne : /home/bumblebee ]

What am I missing here?

Thanks for your replies.

HELLO=world echo $HELLO

In the above, bash does parameter expansion before the statement is executed. That means that $HELLO is replaced with nothing (or whatever the current value of HELLO is) before the statement is executed (which would include setting HELLO to world).


$ HELLO=world bash -c 'echo $HELLO'

Notice that echo $HELLO is inside single quotes. Single quotes prevent parameter expansion. That means that HELLO is not evaluated until the bash subshell starts up and sees it as an argument. By that time, HELLO will have been set equal to world.

By contrast, consider this line in which the single quotes have been replaced with double quotes:

$ HELLO=world bash -c "echo $HELLO"

Here nothing prints because double-quotes do not suppress parameter expansion. Thus, the bash command is given two arguments -c and echo. Hence, nothing prints.

All the gory details

man bash explains, in detail, what happens when commands such as the above are processed:

When a simple command is executed, the shell performs the following expansions, assignments, and redirections, from left to right.

   1.     The words that  the  parser  has  marked  as  variable
          assignments  (those  preceding  the  command name) and
          redirections are saved for later processing.

   2.     The words that are not variable assignments  or  redi‐
          rections  are  expanded.   If  any  words remain after
          expansion, the first word is taken to be the  name  of
          the command and the remaining words are the arguments.

   3.     Redirections  are  performed  as described above under

   4.     The text after  the  =  in  each  variable  assignment
          undergoes  tilde  expansion, parameter expansion, com‐
          mand substitution,  arithmetic  expansion,  and  quote
          removal before being assigned to the variable.

Consider again the command:

HELLO=world echo $HELLO

The argument to echo undergoes parameter expansion in step 2 while bash does not even begin to assign the new value to HELLO until step 4.

  • Aah ok - makes sense now. Thanks. So, I guess, this is a bash-only feature? – Lakshminarayanan K. Aug 1 '14 at 7:31
  • @LakshminarayananK. It is standard POSIX shell behavior, though I wouldn't call it a "feature." If you think about how a shell goes about processing a command line, it does, however, in its own way, make sense. – John1024 Aug 1 '14 at 16:54

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.