Why doesn't foo=bar echo "$foo" print bar?

This is subtle, and has to do with the exact order in which the BashParser performs each step.

Many people, when they first learn about var=value command and how it temporarily sets a variable for the duration of a command, eventually work up an example like this one and become confused why it doesn't do what they expect.

As an illustration:

$ unset foo
$ foo=bar echo "$foo"

$ echo "$foo"

$ foo=bar; echo "$foo"
bar

The reason the first one prints a blank line is because of the order of these steps:

This version works as we expect:

$ unset foo
$ foo=bar bash -c 'echo "$foo"'
bar

In this case, the following steps are performed:

It's not entirely clear, in all cases, why people ask us this question. Mostly they seem to be curious about the behavior, rather than trying to solve a specific problem; so I won't try to give any examples of "the right way to do things like this", since there's no real problem to solve.

There are some special cases in bash where understanding this can be useful. Take the following examples

  # Allow us to set IFS for 1 assigment
  Array1=( "Var 1" "Var 2" "Var 3" "Var 4" )

  # joins each array element with a ";"
  IFS=";" eval 'echo "${Array1[*]}"' 
  # Var 1;Var 2;Var 3;Var 4

  IFS=";" eval 'JoinedVariable="${Array1[*]}"' 
  echo "${JoinedVariable}"                   
  # Var 1;Var 2;Var 3;Var 4


  # splits the string at ";"
  IFS=";" eval 'Array2=(${JoinedVariable})'  
  IFS="_" eval 'echo "${Array2[*]}"'                    
  # Var 1_Var 2_Var 3_Var 4