简体   繁体   English

Python3子进程输出

[英]Python3 subprocess output

I want to run the Linux word count utility wc to determine the number of lines currently in the /var/log/syslog, so that I can detect that it's growing.我想运行 Linux 字数统计实用程序 wc 来确定 /var/log/syslog 中当前的行数,以便我可以检测到它正在增长。 I've tried various test, and while I get the results back from wc, it includes both the line count as well as the command (eg, var/log/syslog).我尝试了各种测试,当我从 wc 得到结果时,它包括行数和命令(例如,var/log/syslog)。

So it's returning: 1338 /var/log/syslog But I only want the line count, so I want to strip off the /var/log/syslog portion, and just keep 1338.所以它返回:1338 /var/log/syslog 但我只想要行数,所以我想去掉 /var/log/syslog 部分,只保留 1338。

I have tried converting it to string from bytestring, and then stripping the result, but no joy.我尝试将它从字节串转换为字符串,然后剥离结果,但没有任何乐趣。 Same story for converting to string and stripping, decoding, etc - all fail to produce the output I'm looking for.转换为字符串和剥离、解码等的相同故事 - 都无法产生我正在寻找的输出。

These are some examples of what I get, with 1338 lines in syslog:这些是我得到的一些示例,系统日志中有 1338 行:

  • b'1338 /var/log/syslog\n' b'1338 /var/log/syslog\n'
  • 1338 /var/log/syslog第1338章

Here's some test code I've written to try and crack this nut, but no solution:这是我编写的一些测试代码,试图破解这个问题,但没有解决方案:

import subprocess

#check_output returns byte string
stdoutdata = subprocess.check_output("wc --lines /var/log/syslog", shell=True)
print("2A stdoutdata: " + str(stdoutdata))
stdoutdata = stdoutdata.decode("utf-8")
print("2B stdoutdata: " + str(stdoutdata))    
stdoutdata=stdoutdata.strip()
print("2C stdoutdata: " + str(stdoutdata))    

The output from this is:输出是:

  • 2A stdoutdata: b'1338 /var/log/syslog\n' 2A 标准输出数据:b'1338 /var/log/syslog\n'

  • 2B stdoutdata: 1338 /var/log/syslog 2B 标准输出数据:1338 /var/log/syslog

  • 2C stdoutdata: 1338 /var/log/syslog 2C 标准输出数据:1338 /var/log/syslog

  • 2D stdoutdata: 1338 /var/log/syslog 2D 标准输出数据:1338 /var/log/syslog

I suggest that you use subprocess.getoutput() as it does exactly what you want—run a command in a shell and get its string output (as opposed to byte string output).我建议您使用subprocess.getoutput() ,因为它完全符合您的要求 - 在 shell 中运行命令并获取其字符串输出(而不是字节字符串输出)。 Then you can split on whitespace and grab the first element from the returned list of strings.然后,您可以拆分空格并从返回的字符串列表中获取第一个元素。

Try this:尝试这个:

import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])

Since Python 3.6 you can make check_output() return a str instead of bytes by giving it an encoding parameter:从 Python 3.6 开始,您可以通过给它一个编码参数来使check_output()返回一个str而不是bytes

check_output('wc --lines /var/log/syslog', encoding='UTF-8')

But since you just want the count, and both split() and int() are usable with bytes , you don't need to bother with the encoding:但是由于您只需要计数,并且split()int()都可以与bytes一起使用,因此您无需费心编码:

linecount = int(check_output('wc -l /var/log/syslog').split()[0])

While some things might be easier with an external program (eg, counting log line entries printed by journalctl ), in this particular case you don't need to use an external program.虽然使用外部程序可能会更容易一些事情(例如,计算由journalctl打印的日志行条目),但在这种特殊情况下,您不需要使用外部程序。 The simplest Python-only solution is:最简单的纯 Python 解决方案是:

with open('/var/log/syslog', 'rt') as f:
    linecount = len(f.readlines())

This does have the disadvantage that it reads the entire file into memory;这样做的缺点是将整个文件读入内存; if it's a huge file instead initialize linecount = 0 before you open the file and use a for line in f: linecount += 1 loop instead of readlines() to have only a small part of the file in memory as you count.如果它是一个巨大的文件,则在打开文件之前初始化linecount = 0for line in f: linecount += 1而不是readlines() ,以便在您计数时只有一小部分文件在内存中。

To avoid invoking a shell and decoding filenames that might be an arbitrary byte sequence (except '\0' ) on *nix, you could pass the file as stdin:为了避免在 *nix 上调用 shell 并解码可能是任意字节序列( '\0'除外)的文件名,您可以将文件作为标准输入传递:

import subprocess

with open(b'/var/log/syslog', 'rb') as file:
    nlines = int(subprocess.check_output(['wc', '-l'], stdin=file))
print(nlines)

Or you could ignore any decoding errors:或者您可以忽略任何解码错误:

import subprocess

stdoutdata = subprocess.check_output(['wc', '-l', '/var/log/syslog'])
nlines = int(stdoutdata.decode('ascii', 'ignore').partition(' ')[0])
print(nlines)

Equivalent to Curt J. Sampson's answer is also this one (it's returning a string):相当于 Curt J. Sampson 的答案也是这个(它返回一个字符串):

subprocess.check_output('wc -l /path/to/your/file | cut -d " " -f1', universal_newlines=True, shell=True)

from docs:来自文档:

If encoding or errors are specified, or text is true, file objects for stdin, stdout and stderr are opened in text mode using the specified encoding and errors or the io.TextIOWrapper default.如果指定了编码或错误,或者 text 为 true,则 stdin、stdout 和 stderr 的文件对象将使用指定的编码和错误或 io.TextIOWrapper 默认值以文本模式打开。 The universal_newlines argument is equivalent to text and is provided for backwards compatibility. Universal_newlines 参数等价于文本,是为了向后兼容而提供的。 By default, file objects are opened in binary mode.默认情况下,文件对象以二进制模式打开。

Something similar, but a bit more complex using subprocess.run():类似的东西,但使用 subprocess.run() 有点复杂:

subprocess.run(command, shell=True, check=True, universal_newlines=True, stdout=subprocess.PIPE).stdout

as subprocess.check_output() could be equivalent to subprocess.run().因为 subprocess.check_output() 可以等价于 subprocess.run()。

getoutput (and the closer replacement getstatusoutput ) are not a direct replacement of check_output - there are security changes in 3.x that prevent some previous commands from working that way (my script was attempting to work with iptables and failing with the new commands). getoutput (以及更接近的替换getstatusoutput )不是check_output的直接替换 - 3.x 中的安全更改阻止了以前的一些命令以这种方式工作(我的脚本试图使用 iptables 并且使用新命令失败)。 Better to adapt to the new python3 output and add the argument universal_newlines=True:更好地适应新的python3输出并添加参数universal_newlines=True:

check_output(command, universal_newlines=True)

This command will behave as you expect check_output, but return string output instead of bytes.该命令的行为与您期望的 check_output 一样,但返回字符串输出而不是字节。 It's a direct replacement.是直接替换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM