4

On Mac 10.11.6, using GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin15) the set +a command appears to not work:

script.py

#!/usr/bin/python
import os
print("VAR0 is:", os.environ.get("VAR0")

Commands:

$ VAR0=abc
$ ./script.py
('VAR0 is:', None)   # expected
$ set -a
$ VAR0=abc
$ ./script.py
('VAR0 is:', 'abc')   # expected, VAR0 has been exported to the environment and script.py has access to it
$ set +a
$ VAR0=def
$ ./script.py
('VAR0 is:', 'def')   # <= unexpected

3 Answers 3

5

You've misunderstood what set -a does. If a variable is exported, changes to that variable are always reflected to the environment. (This wasn't always true of historical implementations of sh, but it's true in all modern, POSIX-compliant(-ish) shells.) The -a option only forces a variable to be exported even if it wasn't before: by default an assignment creates a shell variable, but when -a is in effect the assignment causes the variable to be exported even if it wasn't already.

set +a does unset the -a option. Changing the value of an exported variable affects the environment whether -a is in effect or not.

2
  • Not only when a variable becomes defined but also when a variable is modified (I am talking of what becomes exported if the -a option is in effect, of course)..
    – user232326
    Jun 23, 2017 at 2:41
  • For clarity, since VAR0 in the question was set while set -a was in effect, it was exported and thus stayed that way; even modifications made to it after set +a was called will still modify the exported variable and thus be visible. The "modification" part means that if VAR0 were defined while set +a were in effect (and thus it wasn't exported) but was modified after set -a was called, VAR0 would get exported upon the modification (and stay that way even if set +a is called again).
    – Doktor J
    Mar 15, 2018 at 20:42
3

Take away: Yes, set +a unsets set -a but variables do not become un exported because of that. Each variable then needs to be un exported or unset.


The option allexport (Same as set -a) allows for automatic export of new and changed variables. Variables that exist before activating the set -a option will not be exported.

Two points before testing:

  1. The condition of set -a could be printed with shopt -po allexport.
    And could be changed with shopt -os allexport and shopt -ou allexport.

    $ shopt -po allexport
    set +o allexport
    
    $ set -a
    $ shopt -po allexport
    set -o allexport
    
    $ set +a
    $ shopt -po allexport
    set +o allexport
    
  2. The shell way to test environment variables is to examine the output of the environment command, actually to grep it

    $ env | grep PATH
    PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    

No need for an external program from python (that needs compiling on first call). You may still use it if that makes you happy, but there is no real need for that.

If the option is unset (set +a). A new variable will not be exported.

$ unset VAR0
$ VAR0=abc
$ env | grep VAR0
                      # nothing is printed.

Or, if you still want your program:

$ ./envtest.py
VAR0 is: None

If the -a option is changed, the var will not be exported until changed:

$ set -a
$ shopt -po allexport
set -o allexport
$ env | grep VAR0
$ ./envtest.py
VAR0 is: None

If the variable change:

$ VAR0=bcd
$ env | grep VAR0
VAR0=bcd
$ ./envtest.py
VAR0 is: bcd

But the variable will remain in the environment if the set +a is applied:

$ set +a
$ env | grep VAR0
VAR0=bcd
$ ./envtest.py
VAR0 is: bcd

Even if the var is changed, it is still part of the environment:

$ VAR0=xyz
$ env | grep VAR0
VAR0=xyz
$ ./envtest.py
VAR0 is: xyz

Until it is either un exported (remove the export attribute):

$ declare +x VAR0

Or it is simply unset

$ env | grep VAR0
VAR0=xyz
$ unset VAR0
$ env | grep VAR0

No, assigning an empty value is not the same:

$ VAR0=''
$ env | grep VAR0
VAR0=

Which your program doesn't show that clearly:

$ ./envtest.py
VAR0 is: 
2

This is because the assignment to the local shell variable is now affecting the environment variable. If you first unset the variable then future assignments only work on the local shell variable as before:

$ unset VAR0
$ VAR0=def
$ ./script.py
('VAR0 is:', 'None')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.