This comes down to a question of how evaluation works. Both examples work in the same way, the problem happens because of how the shell (bash, here) expands variables.
When you write this command:
HOME="foo" echo $HOME
$HOME is expanded before the command is run. Therefore, it is expanded to the original value and not the new one you have set it to for the command. The
HOME variable has indeed been changed in the environment that the
echo command is running in, however, you are printing the
$HOME from the parent.
To illustrate, consider this:
$ HOME="foo" bash -c 'echo $HOME'
$ echo $HOME
As you can see above, the first command prints the temporarily changed value of
HOME and the second prints the original, demonstrating that the variable was only changed temporarily. Because the
bash -c ... command is enclosed in single quotes (
' ') instead of double ones (
" "), the variable is not expanded and is passed as-is to the new bash process. This new process then expands it and prints the new value it has been set to. You can see this happen if you use
$ set -x
$ HOME="hello" echo "$HOME"
+ echo /home/terdon
As you can see above, the variable
$HOME is never passed to
echo. It only sees its expanded value. Compare with:
$ HOME="hello" bash -c 'echo $HOME'
+ bash -c 'echo $HOME'
Here, because of the single quotes, the variable and not its value are passed to the new process.