68

In Bash, we can set an environment variable for a single command this way:

FOO=bar somecommand

What if we want to unset a variable for a single command?

codeforester
  • 39,467
  • 16
  • 112
  • 140

4 Answers4

66

Technically, they're not environment variables until someone exports them. But you can at least set them to empty:

FOO= some command

If removing them from the environment is enough, you can use env:

env -u FOO somecommand
JB.
  • 40,344
  • 12
  • 79
  • 106
  • 26
    You can also use a subshell: `(unset FOO; some command)`. But anyway, I consider empty environment variables to be different from absent environment variables, so I wouldn't use the `FOO= some command` approach. – C. K. Young Sep 19 '13 at 23:10
  • 1
    (So do I). (OHAI cky, it's been a long time!) – JB. Sep 19 '13 at 23:16
  • 4
    Technically they are environment variables, just not for the current environment: [the variables are added to the environment of the executed command and do not affect the current shell environment](http://www.gnu.org/software/bash/manual/bashref.html#Simple-Command-Expansion) – glenn jackman Sep 19 '13 at 23:26
  • 1
    @glennjackman No, what JB is saying is that running `FOO=bar` by itself does not set an environment variable, unless `FOO` is exported. – C. K. Young Sep 19 '13 at 23:32
  • I just glanced at the bash doc again and it actually uses the term environment for the shell's local variables as well. But for the non-exported ones I'd consider that an implementation detail indeed. I'm not going to check whether it calls `setenv` just this evening. – JB. Sep 19 '13 at 23:43
  • 3
    @JB: it doesn't call setenv for exported variables either, but it does add them to the list of environment variables passed to child processes. Since bash doesn't really distinguish between environment variables and other types of variables, the result of `export` isn't particularly visible in the shell in which is was performed. (Of course, you can see the difference with `declare -p`.) Regardless of how you feel about empty and absent variables, bash doesn't really distinguish between them either, unless you `set -u` -- and if you do, a lot of standard scripts will break. – rici Sep 20 '13 at 00:17
  • Setting the variable to be empty worked for my purpose (although I wasn't expecting it to). Thanks! – skeptical scientist Sep 20 '13 at 16:06
  • @rici, as a `command` there might be a `make` which differs which environment variables are unset and which are simply empty. – ony Apr 26 '15 at 07:02
  • @JB., for that specific command `FOO` will be set as an environment variable – ony Apr 26 '15 at 07:04
22
env -u FOO somecommand

This will remove the environment variable FOO from the somecommand process' environment.

And to unset multiple variables:

env -u FOO -u FOO2 somecommand
qwertzguy
  • 15,699
  • 9
  • 63
  • 66
3

For anyone intending to run a command with none of their environment variables, you can do so by running:

env -i somecommand
Travis
  • 13,311
  • 4
  • 26
  • 40
2

This is tricky when "somecommand" is a shell function.

One-shot environment variable assignments, such as 'FOO' in "FOO=bar cmd", exist only during the invocation of 'cmd'.
However, if 'cmd' happens to be a shell function, then 'FOO' is assigned in the executing shell itself, and that assignment remains until the process exits (unless explicitly unset).
Since this side-effect of "FOO=bar shell_func" is unlikely to be intentional, it should be avoided.

To further illustrates how the FOO= aCommand is dangerous, consider Git 2.26 (Q1 2020), which avoids "FOO= shell_function (unsetting FOO just for one command).

See commit d6509da, commit a7fbf12, commit c7973f2 (26 Dec 2019) by Jonathan Nieder (artagnon).
(Merged by Junio C Hamano -- gitster -- in commit c7372c9, 30 Jan 2020)

fetch test: avoid use of "VAR= cmd" with a shell function

Signed-off-by: Jonathan Nieder

Just like assigning a nonempty value, assigning an empty value to a shell variable when calling a function produces non-portable behavior: in some shells, the assignment lasts for the duration of the function invocation, and in others, it persists after the function returns.

Use an explicit subshell with the envvar exported to make the behavior consistent across shells and crystal clear.

All previous instances of this pattern used "VAR=value" (with nonempty value), which is already diagnosed automatically by "make test-lint" since a0a630192d (t/check-non-portable-shell: detect "FOO=bar shell_func", 2018-07-13).

For example, instead of:

GIT_TEST_PROTOCOL_VERSION= trace_fetch client origin to_fetch

Use a subshell:

(
    GIT_TEST_PROTOCOL_VERSION= &&
    export GIT_TEST_PROTOCOL_VERSION &&
    trace_fetch client origin to_fetch
) &&
...
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250