<> == 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 -v 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: * The parameter expansion of `$foo` is done first. An empty string is substituted for the quoted expression. * After that, Bash sets up a temporary environment and puts `foo=bar` in it. * The `echo` command is run, with an empty string as an argument, and `foo=bar` in its environment. But since `echo` doesn't care about environment variables, it ignores that, and prints only a newline. This version works as we expect: {{{ $ unset -v foo $ foo=bar bash -c 'echo "$foo"' bar }}} In this case, the following steps are performed: * A temporary environment is set up with `foo=bar` in it. * `bash` is invoked within that environment, and given `-c` and `echo "$foo"` as its two arguments. * The child Bash process expands `$foo` using the value from the environment and hands that value to `echo`. * `echo` receives `bar` as its only argument, and prints it, plus a newline. 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. ----- * '''In The Manual — [[https://www.gnu.org/software/bash/manual/html_node/Simple-Command-Expansion.html#Simple-Command-Expansion|Simple Command Expansion]]''' ----- There are some special cases in Bash where understanding this can be useful. Take the following example: {{{ arr=('Var 1' 'Var 2' 'Var 3' 'Var 4') # join each array element with a ";" # Traditional solution: set IFS, then unset it afterward IFS=\; joinedVariable="${arr[*]}" unset -v IFS # Alternative one: temporarily set IFS for the duration of eval. # Double-quotes work around a Bash bug in versions < 4.3.0 IFS=\; command eval 'JoinedVariable="${arr[*]}"' # Alternative two: a function. Local variables are not POSIX (as of 2017). # Usage: join joinchar [arg ...] join() { local IFS="$1" shift printf '%s\n' "$*" } }}} Here, the `eval` alternative is simpler and more elegant than unsetting [[IFS]] (''In your opinion! -- GreyCat''). Appropriate care must be taken [[BashFAQ/048|to ensure safety when using eval]]. The `command` prefix is required for all shells other than Bash plus Bash POSIX mode (see [[http://wiki.bash-hackers.org/commands/builtin/eval#using_the_environment]]). This won't work in recent versions of zsh due to an apparent regression (documented behavior broken for `setopt POSIX_BUILTINS`), or busybox due to a bug in that environment assignments fail to propagate in this case. (feel free to file bugs if anybody cares enough.)