设置 PYTHONPATH 时遇到一些未找到模块的异常,然后执行一些 py 脚本:
$PYTHONPATH=somepath/a/b
$python myscript.py
Exception has occurred: ModuleNotFoundError (note: full exception trace is shown but execution is paused at: _run_module_as_main)
No module named 'c'
但是如果我导出 PYTHONPATH,一切正常
$export PYTHONPATH=somepath/a/b
$python myscript.py
==>ok
当我内联 PYTHONPATH 分配时它也起作用:
$PYTHONPATH=somepath/a/b python myscript.py
==>ok
为什么我们会有这种行为?
“为什么……?” -- 因为您在 Unix 或类 Unix(例如 WSL)上使用传统(Bourne/Korn 系列)shell,尽管您没有在 Q 中识别出是哪个。这是 POSIX 所需的 shell 类型,并且经常这样描述。其他 Unixy shell(例如 csh-family 或 Fish)是不同的,Windows 命令处理器也是如此。
在 POSIX shell 中,每个变量都有一个属性来选择是否“导出”,即当作为子进程运行 python(或脚本)等程序时,作为
环境变量(操作系统功能)传递).
以下任何命令或序列(可能被其他不相关的命令分隔)将变量设置为“导出”:
export foo=bar
export foo; foo=bar
foo=bar; export foo
typeset -x foo=bar
typeset -x foo; foo=bar
foo=bar; typeset -x foo
# in many Bourne/Korn shells declare is another name for typeset
IF 设置了 shell 选项 -a
,简单的赋值
foo=bar
还设置了导出属性。这些设置是“永久”的;导出的变量将传递给随后运行的所有程序(和脚本),除非明确取消设置或更改或 shell 退出。
此外,简单命令开头的“单词”
foo=bar
,在指定要运行的程序的单词之前,仅为该命令/进程添加或替换环境变量——除非命令是 shell 内置的,在这种情况下,POSIX 行为未指定,实际 shell 可能会有所不同。 但是赋值
foo=bar
本身 - 不是作为简单命令的前缀,并且前面或后面没有设置导出属性,并且没有选项
-a
生效 - 只设置一个 shell变量,该变量是不是“导出”,因此它不会传递给子进程(例如 python)或被子进程看到。