[bash] How to print / echo environment variables?

To bring the existing answers together with an important clarification:

As stated, the problem with NAME=sam echo "$NAME" is that $NAME gets expanded by the current shell before assignment NAME=sam takes effect.

Solutions that preserve the original semantics (of the (ineffective) solution attempt NAME=sam echo "$NAME"):

Use either eval[1] (as in the question itself), or printenv (as added by Aaron McDaid to heemayl's answer), or bash -c (from Ljm Dullaart's answer), in descending order of efficiency:

NAME=sam eval 'echo "$NAME"'  # use `eval` only if you fully control the command string
NAME=sam printenv NAME
NAME=sam bash -c 'echo "$NAME"'

printenv is not a POSIX utility, but it is available on both Linux and macOS/BSD.

What this style of invocation (<var>=<name> cmd ...) does is to define NAME:

  • as an environment variable
  • that is only defined for the command being invoked.

In other words: NAME only exists for the command being invoked, and has no effect on the current shell (if no variable named NAME existed before, there will be none after; a preexisting NAME variable remains unchanged).

POSIX defines the rules for this kind of invocation in its Command Search and Execution chapter.


The following solutions work very differently (from heemayl's answer):

NAME=sam; echo "$NAME"
NAME=sam && echo "$NAME"

While they produce the same output, they instead define:

  • a shell variable NAME (only) rather than an environment variable
    • if echo were a command that relied on environment variable NAME, it wouldn't be defined (or potentially defined differently from earlier).
  • that lives on after the command.

Note that every environment variable is also exposed as a shell variable, but the inverse is not true: shell variables are only visible to the current shell and its subshells, but not to child processes, such as external utilities and (non-sourced) scripts (unless they're marked as environment variables with export or declare -x).


[1] Technically, bash is in violation of POSIX here (as is zsh): Since eval is a special shell built-in, the preceding NAME=sam assignment should cause the the variable $NAME to remain in scope after the command finishes, but that's not what happens.
However, when you run bash in POSIX compatibility mode, it is compliant.
dash and ksh are always compliant.
The exact rules are complicated, and some aspects are left up to the implementations to decide; again, see Command Search and Execution.
Also, the usual disclaimer applies: Use eval only on input you fully control or implicitly trust.