Python3 子进程输出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18244126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python3 subprocess output
提问by user2565677
I'm wanting to run the Linux word count utility wc to determine the number of lines currently in the /var/log/syslog, so I can detect that it's growing. 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 (e.g., var/log/syslog).
我想运行 Linux 字数统计实用程序 wc 来确定 /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'
- 1338 /var/log/syslog
- b'1338 /var/log/syslog\n'
- 第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'
2B stdoutdata: 1338 /var/log/syslog
2C stdoutdata: 1338 /var/log/syslog
2D stdoutdata: 1338 /var/log/syslog
2A 标准输出数据:b'1338 /var/log/syslog\n'
2B 标准输出数据:1338 /var/log/syslog
2C 标准输出数据:1338 /var/log/syslog
二维标准输出数据:1338 /var/log/syslog
采纳答案by Joseph Dunn
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 stringoutput). Then you can split on whitespaceand grab the first element from the returned list of strings.
我建议您使用subprocess.getoutput()
它,因为它完全符合您的要求——在 shell 中运行命令并获取其字符串输出(而不是字节字符串输出)。然后,您可以拆分空格并从返回的字符串列表中获取第一个元素。
Try this:
尝试这个:
import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])
回答by jfs
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:
为了避免'\0'
在 *nix 上调用 shell 和解码可能是任意字节序列(除了)的文件名,您可以将文件作为标准输入传递:
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)
回答by cjs
Since Python 3.6 you can make check_output()
return a str
instead of bytes
by giving it an encodingparameter:
从 Python 3.6 开始,您可以check_output()
返回 astr
而不是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 (e.g., counting log line entries printed by journalctl
), in this particular case you don't need to use an external program. The simplest Python-only solution is:
虽然使用外部程序可能会使某些事情更容易(例如,计算由 打印的日志行条目journalctl
),但在这种特殊情况下,您不需要使用外部程序。最简单的 Python-only 解决方案是:
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 = 0
在打开文件之前进行初始化并使用for line in f: linecount += 1
循环而不是在计算readlines()
时只在内存中保留一小部分文件。
回答by Catalin B.
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. The universal_newlines argument is equivalent to text and is provided for backwards compatibility. By default, file objects are opened in binary mode.
如果指定了编码或错误,或者 text 为真,则使用指定的编码和错误或 io.TextIOWrapper 默认值以文本模式打开 stdin、stdout 和 stderr 的文件对象。Universal_newlines 参数等效于 text 并提供向后兼容性。默认情况下,文件对象以二进制模式打开。
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()。