What is the difference between:
prompt$ TSAN_OPTIONS="suppressions=/somewhere/file" ./myprogram
and
prompt$ TSAN_OPTIONS="suppressions=/somewhere/file"
prompt$ ./myprogram
The thread-sanitizer library gives the first case as how to get their library (used within myprogram) to read the file given in options. I read it, and assumed it was supposed to be two separate lines, so ran it as the second case.
The library doesn't use the file in the second case, where the environment variable and the program execution are on separate lines.
What's the difference?
Bonus question: How does the first case even run without error? Shouldn't there have to be a ; or && between them? The answer to this question likely answers my first...
The format VAR=value command
sets the variable VAR
to have the value value
in the environment of the command command
. The spec section covering this is the Simple Commands. Specifically:
Otherwise, the variable assignments shall be exported for the execution environment of the command and shall not affect the current execution environment except as a side-effect of the expansions performed in step 4.
The format VAR=value; command
sets the shell variable VAR
in the current shell and then runs command
as a child process. The child process doesn't know anything about the variables set in the shell process.
The mechanism by which a process exports (hint hint) a variable to be seen by child processes is by setting them in its environment before running the child process. The shell built-in which does this is export
. This is why you often see export VAR=value
and VAR=value; export VAR
.
The syntax you are discussing is a short-form for something akin to:
VAR=value
export VAR
command
unset -v VAR
only without using the current process environment at all.
To complement Etan Reisner's helpful answer:
It's important to distinguish between shell variables and environment variables:
Note: The following applies to all POSIX-compatible shells; bash
-specific extensions are marked as such.
A shell variable is a shell-specific construct that is limited to the shell that defines it (with the exception of subshells, which get their own copies of the current shell's variables),
whereas an environment variable is inherited by any child process created by the current process (shell), whether that child process is itself a shell or not.
Note that all-uppercase variable names should only be used for environment variables.
Either way, a child process only ever inherits copies of variables, whose modification (by the child) does not affect the parent.
- All environment variables are also shell variables (the shell ensures that),
- but the inverse is NOT true: shell variables are NOT environment variables, unless explicitly designated or inherited as such - this designation is called exporting.
- note that the off-by-default
-a
shell option (set with set -a
, or passed to the shell itself as a command-line option) can be used to auto-export all shell variables.
Thus,
- any variables you create implicitly by assignment - e.g.,
TSAN_OPTIONS="suppressions=/somewhere/file"
- are ONLY shell variables, but NOT ALSO environment variables,
- EXCEPT - perhaps confusingly - when prepended directly to a command - e.g.
TSAN_OPTIONS="suppressions=/somewhere/file" ./myprogram
- in which case they are ONLY environment variables, only in effect for THAT COMMAND.
- This is what Etan's answer describes.
Shell variables become environment variables as well under the following circumstances:
- based on environment variables that the shell itself inherited, such as
$HOME
- shell variables created explicitly with
export varName[=value]
or, in bash
, also with declare -x varName[=value]
- by contrast, in
bash
, using declare
without -x
, or using local
in a function, creates mere shell variables
- shell variables created implicitly while the off-by-default
-a
shell option is in effect (with limited exceptions)
Once a shell variable is marked as exported - i.e., marked as an environment variable - any subsequent changes to the shell variable update the environment variable as well; e.g.:
export TSAN_OPTIONS # creates shell variable *and* corresponding environment variable
# ...
TSAN_OPTIONS="suppressions=/somewhere/file" # updates *both* the shell and env. var.
export -p
prints all environment variables
unset [-v] MYVAR
undefines shell variable $MYVAR
and also removes it as an environment variable, if applicable.
- in
bash
:
- You can "unexport" a given variable without also undefining it as a shell variable with
export -n MYVAR
- this removes MYVAR
from the environment, but retains its current value as a shell variable.
declare -p MYVAR
prints variable $MYVAR
's current value along with its attributes; if the output starts with declare -x
, $MYVAR
is exported (is an environment variable)