subprocess.Popen("echo $HOME"... 和 subprocess.Popen(["echo", "$HOME"]

Posted

技术标签:

【中文标题】subprocess.Popen("echo $HOME"... 和 subprocess.Popen(["echo", "$HOME"] 有啥区别?【英文标题】:What's the difference between subprocess.Popen("echo $HOME"... and subprocess.Popen(["echo", "$HOME"]subprocess.Popen("echo $HOME"... 和 subprocess.Popen(["echo", "$HOME"] 有什么区别? 【发布时间】:2020-04-25 17:55:18 【问题描述】:

我无法理解它与 bash 相关或 python 子进程,但结果不同:

>>> subprocess.Popen("echo $HOME", shell=True, stdout=subprocess.PIPE).communicate()
(b'/Users/mac\n', None)
>>> subprocess.Popen(["echo", "$HOME"], shell=True, stdout=subprocess.PIPE).communicate()
(b'\n', None)

为什么第二次只是换行符?争论在哪里消失?

【问题讨论】:

Actual meaning of shell=True in subprocess的可能重复 【参考方案1】:

subprocess.Popen() 的第一个参数告诉系统要运行什么。

当它是一个列表时,您需要使用shell=False。巧合的是,它在 Windows 中按您希望的那样工作;但在类 Unix 平台上,您只需传入一些通常会被忽略的参数。实际上,

/bin/sh -c 'echo' '$HOME'

这只会导致第二个参数不用于任何内容(我使用单引号来强调这些只是静态字符串)。

以我的拙见,在这种情况下,Python 应该会抛出错误。在 Windows 上也是如此。这是一个应该被捕获并报告的错误。

(在相反的情况下,如果指定了shell=False,但你传入的字符串不是有效命令的名称,你最终还是会得到一个错误,如果你有一个模糊的想法,这是有道理的发生了什么事。)

如果你真的知道你在做什么,你可以让第一个参数访问后面的参数;例如

/bin/sh -c 'printf "%s\n" "$@"' 'ick' 'foo' 'bar' 'baz'

将在单独的行上打印 foobarbaz。 (“第零个”参数——这里是'ick'——用于填充$0。)但这只是一个模糊的推论;不要试图将它用于任何事情。

另外,如果您只想运行命令,则不应使用subprocess.Popen()subprocess.run() 文档更详细地告诉您这一点。使用text=True 你会得到一个字符串而不是字节。

result = subprocess.run('echo "$HOME"', shell=True,
    text=True, capture_output=True, check=True)
print(result.stdout, result.stderr)

当然,os.environ['HOME'] 允许您从 Python 中访问 $HOME 的值。这也可以让你avoid shell=True which you usually should if you can.

【讨论】:

有关(很多)更多详细信息,另请参阅***.com/questions/4256107/…【参考方案2】:

在https://docs.python.org/2/library/subprocess.html#popen-constructor 上的文档中,如果您查看shell 参数,您会发现

shell 参数(默认为 False)指定是否使用 shell 作为程序来执行。如果 shell 为 True,建议将 args 作为字符串而不是序列传递。

这意味着当您执行第二个命令时,它会以echo 运行,因此您只会得到一个新行。

【讨论】:

【参考方案3】:

当您拥有shell=True 时,实际运行的进程是shell 进程,即认为它在unix 上运行/bin/sh -c。您传递给 Popen 的参数作为参数传递给这个 shell 进程。所以/bin/sh -c 'echo' '$HOME' 打印换行符,第二个参数被忽略。所以通常你应该只使用带有shell=True 的字符串参数。

【讨论】:

以上是关于subprocess.Popen("echo $HOME"... 和 subprocess.Popen(["echo", "$HOME"] 的主要内容,如果未能解决你的问题,请参考以下文章

从 subprocess.Popen 调用“源”命令

如何将 Subprocess.popen() 与 pyinstaller 一起使用?

如何在 Python 2 中将字符串传递给 subprocess.Popen? [复制]

“subprocess.Popen” - 检查成功和错误

将python中的双引号shell命令传递给subprocess.Popen()?

Windows 上的 Python 2.6:如何使用“shell=True”参数终止 subprocess.Popen?