将变量传递给Subprocess.Popen

GaN*_*aNi 9 python subprocess

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

servers[server]['address']
servers[server]['port']
servers[server]['pass']
Run Code Online (Sandbox Code Playgroud)

我无法执行命令

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)
Run Code Online (Sandbox Code Playgroud)

jfs*_*jfs 8

下降shell=True.该参数Popen()是区别对待Unix上,如果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()
Run Code Online (Sandbox Code Playgroud)

请注意,shell=True使用外部输入传递命令存在安全隐患,如文档中的警告所述.


bab*_*unk 5

调用时,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)
Run Code Online (Sandbox Code Playgroud)

这是因为,如果您传递一个列表,则Popen假定您已经将命令行分割成多个单词(以结尾的值sys.argv),因此不需要这样做。

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

解决该问题的另一种方法是将所有单词连接成一个字符串(然后Popen将其拆分,请参见参考资料subprocess.list2cmdline)。但是,如果可能的话,最好使用列表版本-它可以更轻松地控制命令行的分割方式(例如,如果参数中包含空格或引号),而不必弄乱引号引起来。


Mic*_*ian 5

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
Run Code Online (Sandbox Code Playgroud)

如果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)
Run Code Online (Sandbox Code Playgroud)

注1:构造commandshell=True潜在不安全性。用于pipes.quote()减少注射可能性。
注 2pipes.quote()已弃用python2;供python3使用shlex模块。