为什么我需要 shell=True 才能使 Python 的 subprocess.check_output 起作用?

Why do I need shell=True here in order for Python's subprocess.check_output to work?

我有一个 python 脚本 运行 来自 if-up 脚本,由 ppp 程序在 Linux 上当建立 PPP 连接时。 python 脚本基本上调用命令行程序,解析结果并 returns 它:

import subprocess

result = subprocess.check_output(["fw_printenv", "serialnr"])
result = # some operation 
return result

尽管当我从命令行(例如 python script.py)手动 运行 python 脚本时这段代码可以 100% 正常工作,但当它是 运行 来自 if-up 的 PPP。调用 subprocess.check_output 时引发异常:[Errno 2] No such file or directory: 'fw_printenv'.

如果我将代码更改为:

,我只能让它工作
result = subprocess.check_output("fw_printenv serialnr", shell=True)

为什么?

使用绝对路径:

result = subprocess.check_output(["/full/path/to/fw_printenv", "serialnr"])

您通过 cron 和网络服务器 运行 的东西也是如此。

shell=True 显然打开了一个 shell 但不太明显的是,它还设置了所有环境变量(例如 PATH)——就好像你在 运行ning在您的终端中手动编写脚本。删除 shell=True 并改用绝对路径可能是 best/safest 的选择,如果它有效的话(我认为它会)。

来自subprocess documentation

If shell is True, the specified command will be executed through the shell. This can be useful if you are using Python primarily for the enhanced control flow it offers over most system shells and still want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. However, note that Python itself offers implementations of many shell-like features (in particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and shutil).

环境变量是获取二进制文件路径所必需的(值得注意的是 PATH,包含可能的路径,包括 unix 系统下的 /usr/bin/)。 否则,fw_printenv 可能是