【问题标题】:Execute shell command with pipes in Python在 Python 中使用管道执行 shell 命令
【发布时间】:2017-05-05 10:20:00
【问题描述】:

我是 Python 新手,试过谷歌搜索,但没有帮助..
我需要在管道中调用此类命令(从 mailq 获取最旧的待处理邮件):

mailq |grep "^[A-F0-9]" |sort -k5n -k6n |head -n 1

该命令在 shell 中运行。

在 Python 中我写了以下内容:

 p = subprocess.Popen( 'mailq |grep \"^[A-F0-9]\" |sort -k5n -k6n |head -n 1', shell=True,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
 response = p.communicate()[0]

但我得到这样的输出:

排序:写入失败:标准输出:管道损坏\n排序:写入错误\n

想知道是什么导致了这样的错误?

【问题讨论】:

  • 不确定,但stdin=subprocess.PIPE 似乎是多余的,可能是问题所在。您可能还考虑放弃除mailq 之外的所有内容并在python 中处理输出,而不是调用所有这些额外的程序(我希望有一个模块可以在某处替换mailq)。转义双引号看起来也很可疑,尽管我怀疑这会导致这个问题。
  • @cdarke 试图删除标准输入集,但这没有帮助。所以你建议不要调用 shell 命令,而是使用一些现成的库与 mailq 一起工作?
  • 你没有使用任何我能看到的shell命令,grepsorthead都是独立的程序。正则表达式和排序都是python内置的。

标签: python pipe stdout mail-queue


【解决方案1】:

与其让 shell 负责将您的命令拆分为多个进程并通过管道传输它们,不如自己动手。请参阅here 如何将一个子进程流通过管道传输到另一个子进程。

这样您就可以查看每个步骤的输出(例如,通过将标准输出路由到您的标准输出,仅用于调试)并确定您的整个工作流程是否正常。

看起来有点像这样:

mail_process = subprocess.Popen('mailq', stdin=PIPE, stdout=PIPE, stderr=STDOUT)
grep_process = subprocess.Popen(['grep', '\"^[A-F0-9]"'], stdin=mail_process.stdout, stdout=PIPE, stderr=STDOUT]
...
head_process = subprocess.Popen(["head", ...], ...)
head_process.communicate()[0]

【讨论】:

  • 因为|是一个字符
  • 有效的长代码比无效的短代码要好。或者也许这就是我。
【解决方案2】:

我建议你使用这里写的子流程:http://kendriu.com/how-to-use-pipes-in-python-subprocesspopen-objects

ls = subprocess.Popen('ls /etc'.split(), stdout=subprocess.PIPE)
grep = subprocess.Popen('grep ntp'.split(), stdin=ls.stdout, stdout=subprocess.PIPE)
output = grep.communicate()[0]

这是使用管道的pythonic方式。

【讨论】:

    【解决方案3】:

    我认为这应该可行:

    p = subprocess.Popen( 'mailq |grep \"^[A-F0-9]\" |sort -k5n -k6n |head -n 1', shell=True,
                             stdin=subprocess.PIPE,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
    response = p.stdout.readlines(-1)[0]
    print response
    

    打印响应的第一行

    【讨论】:

    • ups,现在修复它
    • 不知道为什么,但实际上您的答案给出了正确的响应,略有变化:p.stdout.readline(-1)。我的意思是为什么管道不再出现错误?!
    • 啊,出于某种原因,我认为您只需要第一行。是的,删除 '[0]' 会给出完整的输出。
    • 但为什么这个解决方案有效,而带有 .communicate 的解决方案显示错误?你能提供一些解释吗.. 我只是想了解脚本(虽然我不是专业的 Python 开发人员,但仍然是技术债务,不了解所写的内容)。谢谢!
    • 我自己不是专业的 Python 开发人员,我是结构工程师,使用 Python 来自动化一些任务。我无法为您提供某种解释,因为 p.communicate()[0] 对于我测试的命令对我来说效果很好。问题可能是 p.stdout 等待进程完成并且通信不,此外,通信允许与您的命令交互并发送新的标准输入,而标准输出仅用于输出。
    【解决方案4】:

    Python3

    shell = subprocess.run(["./snmp.sh","10.117.11.55","1.3.6.1.4.1.43356.2.1.2.1.1.0"],check=True,capture_output=True)
    print(shell)
    

    #!/bin/bash
    args=("$@")
    
    snmpwalk -v 1 -c public ${args[0]} ${args[1]}
    output = subprocess.check_output(["awk",'{print$4}'"],input=shell.stdout,capture_output=True)
    print(output) 
    

    我遇到了这样的错误

    输出 = [Errno 2] 没有这样的文件或目录:“awk '{print $4}'”

    我修复错误的地方只是在 sh 文件的末尾添加了一个管道。

    #!/bin/bash
    args=("$@")
    
    snmpwalk -v 1 -c public ${args[0]} ${args[1]} | awk '{print $4}'
    

    希望对某人有所帮助

    【讨论】:

      最近更新 更多