subprocess.Popen(“ echo $ HOME”…和subprocess.Popen([“ echo”,“ $ HOME”]之间有什么区别


问题内容

我无法获得它与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)

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


问题答案:

第一个参数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。(这里使用“
zeroth”自变量-'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']可以让您$HOME在Python中访问的值。这也使您可以避免shell=True,如果可以的话,通常应避免这种情况。