subprocess.Popen执行ssh命令时遇到问题
我正在使用subprocess.Popen来执行操作系统的命令。这里是我想在代码中模拟的内容:
ssh -T myhost < /path/to/some/file
这样做是可以正常工作的:
def runWorkerCode(filer, filename):
command = "/usr/bin/ssh -T " + filer + " < /devel/myscript"
try:
p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
out, _ = p.communicate()
except Exception:
print "Error: %s" % Exception
sys.exit(1)
return out.rstrip().split('\n')
但是下面这些调用Popen的方式就不行:
p = subprocess.Popen(["/usr/bin/ssh", "-T", filer, "<", "/devel/myscript"], stdout=subprocess.PIPE, shell=True)
p = subprocess.Popen(["/usr/bin/ssh -T", filer, "< /devel/myscript"], stdout=subprocess.PIPE, shell=True)
我尝试了几种其他组合,但唯一能正常工作的方式是先定义一个命令变量,然后把它传给Popen()
。我也试过shell=False
。
第一种方法有效,但我觉得后面那种方式看起来更“干净”。
为什么Popen
不允许我用列表来指定参数呢?
1 个回答
2
在UNIX系统中,当你使用 shell=True
时,应该把参数作为一个字符串提供。如果你提供的是一个列表,subprocess
会把列表中的第一个项当作整个命令字符串,而把列表中其余的项当作传给shell的参数,而不是你的命令。所以在你上面的例子中,结果可能会变成这样:
/bin/sh -T filer < /dev/myscript -c "/usr/sbin/ssh"
这肯定不是你想要的结果!
相反,当你使用 shell=False
时,如果你只运行一个没有参数的单一命令,才可以传一个字符串。如果有参数,就必须把命令作为一个序列传递。而且你也不能通过 <
字符使用shell重定向,因为没有使用shell。
如果你想使用 shell=False
,可以通过 stdin
关键字参数把文件句柄传给 /dev/myscript
:
f = open("/dev/myscript")
p = subprocess.Popen(["/usr/bin/ssh", "-T", filer], stdout=subprocess.PIPE, stdin=f, shell=False)
关于何时传字符串和何时传序列的规则其实挺复杂的,尤其是当你还考虑到Windows的时候。我建议你仔细阅读 文档,试着理解这些内容。可以查看 args
部分和 shell
部分。