使用Python执行带管道的shell命令

3

我是Python的新手,尝试了谷歌搜索,但没有帮助。
我需要在管道中调用这些命令(从邮件队列中获取最旧的待处理邮件):

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排序:写入错误

想知道是什么原因导致了这个错误?

不确定,但 stdin=subprocess.PIPE 似乎是多余的,可能是问题所在。您还可以考虑放弃除 mailq 以外的所有内容,并在 Python 中处理输出,而不是调用所有这些额外的程序(我预计有一个模块可以替换 mailq)。双引号的转义看起来也很可疑,尽管我怀疑这不会导致此问题。 - cdarke
@cdarke试图删除stdin设置,但这并没有帮助。所以您建议不要调用shell命令,而是使用一些准备好的库来处理mailq? - 0x49D1
您没有使用我能看到的任何shell命令,grepsorthead都是独立的程序。正则表达式和排序都内置在Python中。 - cdarke
4个回答

5
我认为这应该有效:
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

打印响应的第一行。

修好了 - UN4
不知道为什么,但实际上您的答案给出了正确的响应,稍作更改即可:p.stdout.readline(-1)。我的意思是,为什么使用管道时不再出现错误?! - 0x49D1
啊,出于某种原因我以为你只需要第一行。是的,去掉 '[0]' 就可以得到完整的输出了。 - UN4
但是为什么这个解决方案有效而使用.communicate的那个会出错呢?你能提供一些解释吗?我只是想理解脚本(虽然我不是专业的Python开发人员,但不理解所写的内容是技术债务)。谢谢! - 0x49D1
1
我本身不是专业的Python开发人员,我是结构工程师,使用Python来自动化一些任务。对于我测试过的命令,p.communicate()[0] 运行良好,但我无法为您提供确切的解释。问题可能在于 p.stdout 等待进程完成,而 communicate 不等待。此外,communicate 允许与您的命令进行交互并发送新的stdin,而stdout仅用于输出。 - UN4
只是为了澄清,communicate() 也会等待进程终止,详见 https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate - UN4

2

不要让shell负责将您的命令拆分为多个进程并将它们进行管道处理,而是自己处理。请参见此处如何将一个子进程流传递到另一个子进程。

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

它会像这样:

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]

因为 | 是一个字符。 - Clintm
2
长而实用的代码总比短小无用的代码好。或许这只适用于我。 - Filip Malczak

1

0

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)

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 文件末尾添加了一个管道。

Shell

#!/bin/bash
args=("$@")

snmpwalk -v 1 -c public ${args[0]} ${args[1]} | awk '{print $4}'

希望能对某些人有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接