3

Why is my zsh doing this?

% MYVAR="hi" echo $MYVAR

% MYVAR="$(date)" echo $MYVAR

% export MYVAR="$(pwd)"
% echo $MYVAR
/Users/theonlygusti

Why are the same-line environment variables apparently not set?

2
  • For me, it works if I do echo ${MYVAR} instead (with {} ). I don't know how it works, though. Something to do with variable expansion I think.
    – zjeffer
    Jan 27, 2022 at 10:00
  • Ah, I think I might have put a semicolon after "hi", which makes it work as well. Sorry for the confusion
    – zjeffer
    Jan 27, 2022 at 18:55

1 Answer 1

8

In the command

MYVAR="hi" echo $MYVAR

the variable MYVAR is set to hi in the environment of the echo command. However, the echo command does not use this variable. It is the current shell that expands the $MYVAR argument on the command line before calling echo.

Therefore, if the MYVAR variable does not exist in the shell beforehand, that command will only output a newline character.

In your last example, you set the variable in the shell before calling echo with the expansion of $MYVAR on the command line. Since the variable is set to the result of $(pwd) at that point (it does not need to be exported), the shell replaces $MYVAR with that value before calling echo.

The difference between

variable=value some-command

and

variable=value; some-command

or the equivalent

variable=value
some-command

is that in the first case, the variable is set to a value in the environment of some-command, but not in the current shell, while in the second/third case, the variable is set in the current shell, and then some-command is called. If variable is additionally exported, then that variable would also be available in the environment of some-command, would it want to use that variable.

Example:

$ unset -v var

Setting a variable at the same time as calling another command sets that variable in the command's environment, but not in the local environment:

$ var=1 sh -c 'printf "var is %s\n" "$var"'
var is 1
$ printf 'var is %s\n' "$var"
var is

Setting a variable in the local environment, but not exporting it sets it locally only:

$ var=1; sh -c 'printf "var is %s\n" "$var"'
var is
$ printf 'var is %s\n' "$var"
var is 1

Exporting the variable makes it available in child processes:

$ export var
$ sh -c 'printf "var is %s\n" "$var"'
var is 1

Note that

MYVAR=$(pwd)

is the same as

MYVAR=$PWD
2
  • I also suggest add another example using eval, for instance: var=1 eval echo '$var', and show the difference between this and the new shell. For instance, when using eval, var=1; eval echo '$var' would still show the value of $var.
    – aviro
    Jan 27, 2022 at 12:04
  • @aviro That would add a level of complexity that I'm not willing to commit to. Also, note that eval should ideally take a single-quoted string: eval 'echo "$var"'. In the bash shell, you'll otherwise invoke the split+glob operation on the value of $var (test with var='1 * 4' in bash). I know this user is using zsh, but that may easily be missed by future readers that just read the answer.
    – Kusalananda
    Jan 27, 2022 at 12:17

Not the answer you're looking for? Browse other questions tagged .