python 为什么向subprocess.ppen传递变量时,尽管传递了一个参数列表,但仍无法正常工作?

cczfrluj  于 2023-03-16  发布在  Python
关注(0)|答案(6)|浏览(125)

我有一个脚本通过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
)
lo8azlld

lo8azlld1#

跌落shell=True . The 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是一个安全隐患,如文档中的警告所述。

bxgwgixi

bxgwgixi2#

当你调用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中的值),因此它不需要这样做。
按照您的说法,它将尝试运行一个名为“pythonmytool.py”的二进制文件,这不是您的意思。
另一种解决方法是将所有的单词连接成一个字符串(Popen将拆分该字符串-请参见subprocess.list2cmdline).但是如果可能的话,最好使用列表版本-它可以更简单地控制命令行如何拆分(例如,如果参数中有空格或引号),而不必纠结于引号字符。

lstz6jyr

lstz6jyr3#

您在为第一个Popen参数键入str时出现问题。请将其替换为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:使用shell=True构造的command可能不安全。使用pipes.quote()以减少注入可能性。
注2pipes.quote()python2以来已弃用;对于python3,请使用shlex模块。

kxxlusnw

kxxlusnw4#

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

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)
ljsrvy3e

ljsrvy3e5#

您可以通过传递

env={whatever_you_want: values} | os.environ

在子进程调用中。

ef1yzkbh

ef1yzkbh6#

使用情况
运行n个shell脚本或python脚本
创建一个run.py文件,负责将参数(整数)传递给shell文件。
假设你想运行n(4)个shell脚本或者python脚本,它们接受1个参数。
用下面的代码创建一个文件run.python
下面的代码说明

  • instanceQty =要运行的shell脚本的数量
  • os.getcwd()=当前文件的路径
  • mockScript.sh=shell脚本,我将其与run.py放在同一目录中

运行shell脚本

# this is python file with name run.py
import subprocess,os
instanceQty = 4
for i in range(0, instanceQty):
    print(os.getcwd())
    subprocess.Popen(f"{os.getcwd()}/mockScript.sh {i}",shell=True,executable='/bin/bash')

运行python脚本

import subprocess,os,sys
instanceQty = 4
for i in range(0, instanceQty):
    print(os.getcwd())
    subprocess.Popen([sys.executable,f"{os.getcwd()}/mockScript.py",str(i)])

运行此文件时使用
Pythonrun.py
MacOS上的权限问题
修改ug+x mockScript.sh
修改ug+x run.py

所有代码均在Python 3.8.1和MacOs 12.0.1环境下测试。

相关问题