将变量传递给Subprocess.Popen

时间:2013-11-22 08:21:06

标签: python subprocess

我有一个脚本,它通过subprocess.Popen模块调用另一个python脚本。但是因为我将参数存储在变量

servers[server]['address']
servers[server]['port']
servers[server]['pass']

我无法执行命令

p = subprocess.Popen(["python mytool.py -a ", servers[server]['address'], "-x", servers[server]['port'], "-p", servers[server]['pass'], "some additional command"], shell=True, stdout=subprocess.PIPE)

4 个答案:

答案 0 :(得分:7)

删除shell=TrueThe arguments to Popen() are treated differently on Unix if shell=True

import sys
from subprocess import Popen, PIPE

# populate list of arguments
args = ["mytool.py"]
for opt, optname in zip("-a -x -p".split(), "address port pass".split()):
    args.extend([opt, str(servers[server][optname])])
args.extend("some additional command".split())

# run script
p = Popen([sys.executable or 'python'] + args, stdout=PIPE)
# use p.stdout here...
p.stdout.close()
p.wait()

请注意,对于带有外部输入的命令,传递shell=True会带来安全隐患,如警告in the docs所述。

答案 1 :(得分:4)

当你致电subprocess.Popen时,你可以传递一个字符串或一个列表来运行命令。如果您传递列表,则应以特定方式拆分项目。

在您的情况下,您需要将其拆分为:

command = ["python",  "mytool.py", "-a", servers[server]['address'], 
           "-x", servers[server]['port'], 
           "-p", servers[server]['pass'], 
           "some",  "additional", "command"]
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

这是因为如果你传入一个列表,Popen假设你已经将命令行拆分为单词(最终会在sys.argv中的值),所以它不需要

你调用它的方式,它将尝试运行一个名为“python mytool.py -a”的二进制文件,这不是你的意思。

另一种解决方法是将所有单词加入一个字符串(Popen然后将其拆分 - 请参阅subprocess.list2cmdline)。但是如果可能的话,你最好使用列表版本 - 它可以更简单地控制命令行的拆分方式(例如,如果参数中包含空格或引号),而不必乱用引号字符。

答案 2 :(得分:2)

第一个str参数类型Popen中的问题。将其替换为list。下面的代码可以工作:

address = servers[server]['address']
port = servers[server]['port']
pass = servers[server]['pass']

command = "python mytool.py -a %s -x %d -p %s some additional command" % (address, port, pass)
p = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
#        it is a list^^^^^^^^^^^^^^^  shell=False

如果command个参数来自受信任的来源,您可以构建command并将其与shell=True一起使用,方式如下:

import pipes as p
command = "python mytool.py -a {} -x {} -p {} some additional command".format(p.quote(address), p.quote(port), p.quote(pass))
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

注意1 :使用command构建shell=True可能不安全。使用pipes.quote()减少注射可能性 注释2 pipes.quote()python2后弃用; python3使用shlex模块。

答案 3 :(得分:1)

您应该将命令连接到整个字符串:

p = subprocess.Popen("python mytool.py -a " + servers[server]['address'] + " -x " + servers[server]['port'] + " -p " + servers[server]['pass'] + " some additional command", shell=True, stdout=subprocess.PIPE)