【问题标题】:How does os.system differ from command line?os.system 与命令行有何不同?
【发布时间】:2018-01-02 23:01:43
【问题描述】:

为什么我的 python 解释器中的 os.system('command') 的输出与终端中的命令不同?

问题解释得很快:

我有

echo $CONFPATH
/home/claramart/Datamart/Parameter

但是

os.system('echo $CONFPATH')

0

这是为什么呢?

详情: 我想获得我的环境 $CONFPATH。我正在使用 python3.5 和 ubuntu16.04.2。

我可以从命令行执行此操作:

echo $CONFPATH
/home/claramart/Datamart/Parameter

这就是我想要的答案。

从命令行将其作为 python 命令执行也可以:

python3 -c 'import os; print(os.environ["CONFPATH"])'
/home/claramart/Datamart/Parameter

问题是,我想从我的 python 解释器而不是从命令行执行它。 从我的 python 解释器执行它不起作用(我使用的是 Pyzo4.4.1):

print(os.environ["CONFPATH"])
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'

我想这完全来自我的解释器,而不是 python 本身,因为从命令行执行 python 是有效的。此外,我可以从我的 python 解释器中获取 $PYTHONPATH,所以我猜它根本没有检测到所有环境变量。

为了避免这种情况并从命令行执行它,我想从我的 python 解释器执行命令行,但是我的 2 个命令行执行都没有按照我想要的方式工作:

os.system('echo $CONFPATH')

0

和:

os.system("""python3 -c 'import os; print(os.environ["CONFPATH"]'""")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'
256

在这两种情况下,它确实适用于 $PYTHONPATH,所以我想它必须在某个时候通过我的解释器,因为我的问题是特定于该变量 $CONFPATH。

为什么我的 python 解释器中的 os.system('command') 与终端中的命令输出不同?

【问题讨论】:

  • 在您的默认 shell 中运行命令,然后您将获得环境。所以:os.system("""/usr/bin/bash -c python3 -c 'import os; print(os.environ["CONFPATH"]'""") - 可能没有正确引用或得到正确的 bash 路径,但希望你明白这一点
  • 我明白了,但是我以前没有使用过这个,os.system("""/bin/bash -c python3 -c 'import os; print(os.environ["CONFPATH"]'""") 启动了一个似乎没有结束的进程,就像它被卡住了一样。也许我做错了?
  • “从我的 python 解释器执行它不起作用(我使用的是 Pyzo4.4.1)”我认为 Pyzo 解释器在具有不同环境变量的不同环境中运行。它在标准解释器中工作吗?
  • @Goyo 它在标准的 python3.5 解释器中也不起作用

标签: python python-3.x command-line os.system pyzo


【解决方案1】:

我认为您希望有一个环境。事实是,每个进程都有自己的环境,通常继承自其父进程。不幸的是,我在你的 sn-ps 中没有看到足够的信息来告诉你如何传递这个特定的值,但我们可以通过它们来看看它们实际上在说什么。

echo $CONFPATH
/home/claramart/Datamart/Parameter

这显示了一个 shell 命令 echo,表明 shell 可以扩展参数 $CONFPATH。但是,它没有显示这是来自 shell 还是环境变量。后来的 sn-ps 确实证明了您确实有一个设置它的环境。

os.system('echo $CONFPATH')

0

这是一个 Python 函数调用,反过来又调用一个 C 库函数,这会导致生成一个新的 shell 并解释给定的命令。值得注意的是,这与您运行的任何 shell 都不相同。它是一个新的 /bin/sh 进程,它从进行调用的 Python 解释器继承环境。我们看到这个 shell 命令成功(退出值 0)并将 CONFPATH 扩展为空,表明它是空的或未设置Python解释器的环境。

python3 -c 'import os; print(os.environ["CONFPATH"])'
/home/claramart/Datamart/Parameter

这里是一个启动 Python 解释器的 shell 命令示例,其中的命令行导致它打印环境变量。它成功了,因为变量是从您运行命令的 shell 继承的。

os.system("""python3 -c 'import os; print(os.environ["CONFPATH"]'""")
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python3.5/os.py", line 725, in __getitem__
    raise KeyError(key) from None
KeyError: 'CONFPATH'
256

这里一个包裹另一个;从 Python 解释器开始,shell 开始运行一个命令,该命令启动另一个 Python 解释器,该解释器应该打印 CONFPATH 环境变量。但是,此内部 Python 代码失败,在其环境中找不到 CONFPATH 时引发 KeyError 异常。这与 shell 的行为相反,后者只是显示一个空值。由于没有捕获到异常,因此打印了一个回溯,Python shell 返回了一个错误代码,然后由 subshel​​l 返回,最后由我们的外部 Python 解释器打印为 256。

您已经展示了在两个不同环境中运行的命令:一个设置了 CONFPATH 的 shell,一个没有设置 CONFPATH 的 Python 解释器。 pstreeps fps -H 可能会帮助您可视化进程树,从而可视化继承环境的位置。注意环境是从父进程拷贝过来的;在父母中改变它只会影响新的孩子,而不是现有的孩子。

在 Linux 中,也可以在 /proc 文件系统中找到环境。例如,tr \\0 \\n &lt; /proc/$$/environ 打印运行它的 shell 的环境(shell 将 $$ 扩展为它自己的进程 ID)。

当您在不同的环境中运行时,这种区别变得更加重要;例如,通过.profile.bashrc 文件设置的任何内容都不会影响从cron 运行的命令,系统启动脚本也是如此。大多数程序保持环境不变,但有些程序会产生特定的例外情况,例如 setuid 程序忽略 LD_LIBRARY_PATH,或 suenv 重写环境。

【讨论】:

  • 惊人的答案。谢谢。
【解决方案2】:

尝试从父 shell(即启动 Python 的 shell)导出 shell 变量:

$ CONFPATH=/home/claramart/Datamart/参数 $ 回声 $CONFPATH /home/claramart/Datamart/参数 $ 环境 | grep 配置路径 $ python3 -c '导入操作系统; print(os.environ["CONFPATH"])' 回溯(最近一次通话最后): 文件“”,第 1 行,在 文件“/usr/lib64/python3.5/os.py”,第 725 行,在 __getitem__ 从无提高 KeyError(key) 键错误:'CONFPATH' $ python3 -c '导入操作系统; print(os.system("echo $CONFPATH"))' 0 # 导出变量后尝试相同的操作 $导出CONFPATH $ 环境 | grep 配置路径 CONFPATH=/home/claramart/Datamart/参数 $ python3 -c '导入操作系统; print(os.environ["CONFPATH"])' /home/claramart/Datamart/参数 $ python3 -c '导入操作系统; print(os.system("echo $CONFPATH"))' /home/claramart/Datamart/参数 0

默认情况下不导出Shell 变量,因此,在上面的export 命令之前,父进程(您的终端的shell)实际上并未导出CONFPATH。如上所示,您的 Python 进程根本不应该在其环境中定义 CONFPATH

话虽如此,我很惊讶地发现在 os.environ 中查找环境变量显然对您有效,而 os.system() 则无效。两者都应该工作,或者都不应该工作,这取决于环境变量的可用性。也许这是使用 Pyzo 或您(或 Pyzo)调用解释器的方式的一个怪癖。

【讨论】:

    猜你喜欢
    • 2011-09-07
    • 1970-01-01
    • 2018-07-26
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    相关资源
    最近更新 更多