1

Observation: environment variables set using the operating system's "read" utility, which contain numeric-only values, aren't accessible in Python's os.environ[] structure, or by node's process.env structure, but ARE accessible to bash.

Expected behavior is that all environment variables are equally accessible from applications, regardless of how they were created.

The same variables, if set using bash using export N=12345 syntax, are accessible. It seems that variable created using the read command are not created equal to other variables in some way that is disturbing node/Python's logic of parsing those variables.

The same variables that are not accessible from node/Python are readily accessible at the bash commandline as shown below in the echo statements.

The read command sets an environment variable based on key-input. It is a convenient way of entering a secret into a variable without leaving a .bash_history record of that secret.

Reproduced on:

  • OSX 10.14.6 ("Mojave") Python 2.7, Python 3.6, node 10.16.3 Linux
  • Kernel 3.10 CentOS 64-bit, Python2.7.5

Sample:

Use read and prompt the user to enter a value for the environment variable named L.

~ $ read L
12345
~ $ python2
Python 2.7.16 (default, Apr 12 2019, 15:32:40) 
[GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.46.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ["L"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/UserDict.py", line 40, in __getitem__
    raise KeyError(key)
KeyError: 'L'
>>> 
~ $ python3
Python 3.7.3 (default, Mar 27 2019, 09:23:15) 
[Clang 10.0.1 (clang-1001.0.46.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.environ["L"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/os.py", line 678, in __getitem__
    raise KeyError(key) from None
KeyError: 'L'
~ $ echo $L
12345

Interestingly, if a numeric variable is set through means other than the read command, they are accessible in Python and node.

>>> os.environ["HISTSIZE"]
'12345678'
2

In the shell, you aren't working with environment variables – you are working with shell variables. The shell just starts off with a copy of its initial environment, but it maintains its own variable namespace.

Shell variables will only be copied back to the environment if they have the 'export' flag. Brand-new variables are not exported by default – it doesn't matter how they were generated, you still need to use the export command to set the right flag on them:

$ read L
12345↵

$ export L

$ python -c 'import os; print("L is", os.environ["L"])'
L is 12345

Note again that this is not specific to read. You can see the same failure if you simply set a variable without using export:

$ N=abcdef

$ python -c 'import os; print("N is", os.environ["N"])'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.7/os.py", line 678, in __getitem__
    raise KeyError(key) from None
KeyError: 'N'

In bash you can use declare -p VAR to check if that variable is currently flagged for export into environment (it'll have the -x option if so).

$ declare -p L N
declare -x L="12345"       # the one that was exported in example 1
declare -- N="abcdef"      # the one that deliberately wasn't, in example 2

(The output is valid as input – e.g. if you actually run declare -x, that is equivalent to export.)


Miscellaneous notes:

  • The environment can only contain string values, but shell variables are not limited to just that – for example, most shells have arrays/lists and dicts.

  • Shells often have variables that one wouldn't want to export. For example, $LINES and $COLUMNS are dynamic within the shell itself, but exporting them would only let programs see a static value, and this would cause problems.

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.