58

我想运行 Linux 字数统计实用程序 wc 来确定 /var/log/syslog 中当前的行数,以便我可以检测到它正在增长。我尝试了各种测试,当我从 wc 得到结果时,它包括行数和命令(例如,var/log/syslog)。

所以它返回:1338 /var/log/syslog 但我只想要行数,所以我想去掉 /var/log/syslog 部分,只保留 1338。

我尝试将它从字节串转换为字符串,然后剥离结果,但没有任何乐趣。转换为字符串和剥离、解码等的相同故事 - 都无法产生我正在寻找的输出。

这些是我得到的一些示例,系统日志中有 1338 行:

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

这是我编写的一些测试代码,试图破解这个问题,但没有解决方案:

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

输出是:

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

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

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

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

4

5 回答 5

77

我建议你subprocess.getoutput()按照你想要的方式使用它——在 shell 中运行一个命令并获取它的字符串输出(而不是字节字符串输出)。然后,您可以拆分空格并从返回的字符串列表中获取第一个元素。

尝试这个:

import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])
于 2013-08-15T00:27:39.180 回答
24

从 Python 3.6 开始,您可以check_output()返回 astr而不是bytes给它一个编码参数:

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

但是由于您只需要计数,并且两者split()int()可以使用bytes,因此您无需费心编码:

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

虽然使用外部程序可能会更容易一些事情(例如,计算由 打印的日志行条目journalctl),但在这种特殊情况下,您不需要使用外部程序。最简单的纯 Python 解决方案是:

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

这样做的缺点是将整个文件读入内存;如果它是一个巨大的文件,则linecount = 0在您打开文件之前进行初始化并使用for line in f: linecount += 1循环而不是readlines()在您计数时仅将文件的一小部分放在内存中。

于 2018-09-13T11:23:54.417 回答
10

为了避免在 *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)

或者您可以忽略任何解码错误:

import subprocess

stdoutdata = subprocess.check_output(['wc', '-l', '/var/log/syslog'])
nlines = int(stdoutdata.decode('ascii', 'ignore').partition(' ')[0])
print(nlines)
于 2013-08-16T10:09:19.300 回答
4

相当于 Curt J. Sampson 的答案也是这个(它返回一个字符串):

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

来自文档:

如果指定了编码或错误,或者 text 为真,则 stdin、stdout 和 stderr 的文件对象将使用指定的编码和错误或 io.TextIOWrapper 默认值以文本模式打开。Universal_newlines 参数等价于文本,是为了向后兼容而提供的。默认情况下,文件对象以二进制模式打开。

类似的东西,但使用 subprocess.run() 有点复杂:

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

因为 subprocess.check_output() 可以等价于 subprocess.run()。

于 2018-12-25T09:54:20.267 回答
1

getoutput(以及更接近的替换getstatusoutput)不是直接替换check_output- 3.x 中的安全更改阻止了以前的一些命令以这种方式工作(我的脚本试图使用 iptables 并且使用新命令失败)。更好地适应新的python3输出并添加参数universal_newlines=True:

check_output(command, universal_newlines=True)

该命令的行为与您期望的 check_output 一样,但返回字符串输出而不是字节。是直接替换。

于 2021-06-24T14:55:26.377 回答