【问题标题】:Subprocess Python.. Stringing together commands子进程 Python .. 将命令串在一起
【发布时间】:2012-05-25 01:18:27
【问题描述】:

我正在编写一个 Python 程序,该程序需要返回在我的一个漏洞扫描中扫描的活动主机。我在返回 XML 之前使用过这种方法,但是当我尝试处理这些额外的程序(例如 cut 和 grep)时,我遇到了问题。也许它不喜欢“管道” |或者也许我在这里用逗号做了一些完全错误的事情,但我已经尝试了各种各样的事情,但似乎无法让它像我从命令行独立运行命令时那样返回结果。非常感谢您提供的任何帮助。

def activeHostsQuery():
    args = ['curl', '-s', '-k', '-H', 'X-Requested-With: curl demoapp', '-u','username:password', 'https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv', '|', 'cut', '-d', '-f1', '|', 'sort', '|', 'uniq', '|', 'grep', '-E', '"\"[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\""', '|', 'wc', '-l']

    activeHostsNumber = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
    return activeHostsNumber

【问题讨论】:

  • 您是否尝试将“shell=True”参数添加到subprocess.Popen
  • activeHostsNumber = subprocess.Popen(args, stdout=subprocess.PIPE, shell=TRUE).communicate()[0] .....这给了我一个“全局名称“TRUE”未定义错误
  • 它必须是“真”,而不是“真”——大小写很重要。
  • curl:尝试“curl --help”或“curl --manual”以获取更多信息。这是我进行这些更改时收到的消息
  • 做到这一点的正确方法是根本不使用任何shell命令。 Python 可以为您完成 curl、cut、sort、grep 和 wc 所做的所有事情。

标签: python linux python-3.x subprocess


【解决方案1】:

将命令串在一起的正确方法是创建多个 Popen 对象。

def activeHostsQuery():
    args1 = ['curl', '-s', '-k',
             '-H', 'X-Requested-With: curl demoapp',
             '-u','username:password',
             'https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv']
    args2 = ['cut', '-d', '-f1']
    args3 = ['sort', '-u']
    args4 = ['grep', '-E', '"\"[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\""']
    args5 = ['wc', '-l']

    p1 = subprocess.Popen(args1, stdout=subprocess.PIPE)
    p2 = subprocess.Popen(args2, stdin=p1.stdout, stdout=subprocess.PIPE); p1.stdout.close()
    p3 = subprocess.Popen(args3, stdin=p2.stdout, stdout=subprocess.PIPE); p2.stdout.close()
    p4 = subprocess.Popen(args4, stdin=p3.stdout, stdout=subprocess.PIPE); p3.stdout.close()
    p5 = subprocess.Popen(args5, stdin=p4.stdout, stdout=subprocess.PIPE); p4.stdout.close()
    activeHostsNumber = p5.communicate()[0]
    return activeHostsNumber

这样做的好处是不涉及 shell - 您可以将任意变量替换到您的参数列表中,而不必担心它们会被字符串拆分、误解、导致重定向或其他任何事情,以及您的参数之间的区别用于生成您的列表将受到尊重。

现在,在这个特殊的案例中,我会在原生 Python 中完成所有事情——当你拥有原生 HTTP 库时,甚至没有理由使用 curl——但知道如何构建管道with subprocess.Popen 在任何情况下都很有用。

【讨论】:

  • 顺便说一句——我很确定这里给 grep 的正则表达式是错误的。我没有更改它,因为它是作为问题的一部分给出的,但是您可能想要去掉其中一组双引号,除非您真的希望 egrep 要求匹配的字符串以 "" 开头和结尾.
  • 恕我直言,这是在 python 中执行此类操作的最佳方法。
【解决方案2】:

我会试试这个:

def activeHostsQuery():
    args = ['curl', '-s', '-k', '-H', 'X-Requested-With: curl demoapp', '-u','username:password', 'https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv', '|', 'cut', '-d', '-f1', '|', 'sort', '|', 'uniq', '|', 'grep', '-E', '"\"[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\""', '|', 'wc', '-l']

    activeHostsNumber = subprocess.Popen(" ".join("'%s'" % a for a in args), shell=True, stdout=subprocess.PIPE).communicate()[0]
    return activeHostsNumber

编辑:在参数周围添加引号。

另一个编辑:好的,试着把命令变成一个字符串:

def activeHostsQuery():
    cmd = 'curl -s -k -H \'X-Requested-With: curl demoapp\' -u username:password \'https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv\' | cut -d, -f1 | sort | uniq | grep -E \'"[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}\\.[[:digit:]]{1,3}"\' | wc -l'

    ctiveHostsNumber = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE).communicate()[0]
    return activeHostsNumber

【讨论】:

  • 进行这些调整后,它只是返回一个空行,程序停止执行
  • 我是否有可能没有在我的 args 中正确的东西周围加上逗号?
  • 我认为您不需要在任何内容周围使用逗号。我对我的解决方案进行了更改,在所有内容中都添加了引号,因为您的某些参数中有空格和特殊字符。
  • 所以我可以从所有 args 中取出所有逗号和单引号?.. 我现在正在尝试但没有太大成功
  • 你准备的args变量是一个字符串列表。每个字符串必须用引号括起来,并用逗号与下一个字符串分隔。但是,当您使用 shell=True 参数时,您不想将字符串列表传递给 subprocess.Popen,而是希望将其传递给单个字符串 - 这就是为什么我的解决方案中有 " ".join("'%s'" % a for a in args) 的原因。
【解决方案3】:

我知道这不能回答问题……但那是 shell 脚本。 如果您希望 shell 脚本将参数传递给 sh -c (或 bash 之类的)

    args = ['sh', '-c', 'curl -s -k -H X-Requested-With: curl demoapp -u','username:password https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv | cut -d -f1 | sort | uniq | grep -E "\"[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\"" | wc -l'


   count = int(cubprcess.check_output(args))

或像其他人建议的那样使用shell=True。如果您关心这些事情,这肯定不会在 Windows 上运行。

你真的应该做这样的事情:

import requests
from csv
from StringIO import StringIO
import re

req=reqeusts.get(
    'https://qualysapi.qualys.com/api/2.0/fo/scan/?action=fetch&scan_ref=scan/1111111.22222&mode=brief&output_format=csv',
    auth=('username','passoword'),
    headers={'X-Requested-With': 'curl demoapp'})

reader = csv.reader(StringIO(req.text))
count = 0
for line in reader:
    if re.match(r'.*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*',line[0]) is not None:
        count += 1

print count

【讨论】:

  • sh -c "one line" "another line" 实际上只处理第一行。 -c 后面的参数是要运行的脚本;之后是传递给脚本的$0,之后是$1,等等。
猜你喜欢
  • 2014-03-15
  • 2019-04-17
  • 1970-01-01
  • 2017-08-28
  • 2017-01-09
  • 2020-11-26
  • 2012-10-31
  • 1970-01-01
  • 2021-12-10
相关资源
最近更新 更多