英文:
Is there a concept of reading the output of a program line by line, as a stream?
问题
我有一个shell命令(例如journalctl -f -o json
),它会连续将行输出到标准输出。
我想逐行检索这个输出并进一步处理它。
os/exec
的文档介绍了如何读取命令的输出,而io
则处理流缓冲。
无论我在哪里查找,处理都是通过一个固定的缓冲区进行的,该缓冲区被读取、处理和进一步写入。我的问题是,这个缓冲区的大小是固定的,与内容无关。
有没有一种方法可以逐行读取输入流(在我的情况下是shell命令的输出)?可能使用比io
读取器更高级的库?
英文:
I have a shell command (e.g. journalctl -f -o json
) that continuously streams lines to the standard output.
I would like to retrieve this output line by line and process it further.
The documentation of os/exec
addresses how to read the output of a command, and io
deals with stream buffering.
Everywhere I looked, the handling goes through a fixed buffer that is read into, handled, and written further. My problem is that the size of this buffer is fixed and independent of the content.
Is there a way to read an incoming stream (in my case - the output of a shell command) line by line? Possibly with a library more high-level than io
readers?
答案1
得分: 2
使用Cmd.StdoutPipe()
来获取进程的输出(通过管道),在使用Cmd.Start()
启动进程之前(Start()
启动命令但不等待其完成)。
使用bufio.Scanner
逐行读取输入(io.Reader
)。
例如,我将使用以下bash脚本,它会打印当前时间3次,每次间隔1秒:
for i in {1..3}; do date; sleep 1; done
示例代码执行并逐行读取其输出:
cmd := exec.Command("bash", "-c", "for i in {1..3}; do date; sleep 1; done")
out, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
defer out.Close()
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
scanner := bufio.NewScanner(out)
for scanner.Scan() {
line := scanner.Text()
fmt.Println("Output:", line)
}
示例输出:
2022/11/29 14:38:48 Output: Tue Nov 29 02:38:48 PM CET 2022
2022/11/29 14:38:49 Output: Tue Nov 29 02:38:49 PM CET 2022
2022/11/29 14:38:50 Output: Tue Nov 29 02:38:50 PM CET 2022
(每行开头的第一个日期时间来自log
包,用于验证每行在延迟1秒后打印,其他时间戳是date
命令的输出。)
英文:
Use Cmd.StdoutPipe()
to obtain the (piped) output of the process before you start it with Cmd.Start()
(Start()
starts the command but does not wait for it to complete).
And use a bufio.Scanner
to read an input (io.Reader
) line-by-line.
For example I'm gonna use this bash script that prints the current time 3 times, sleeping 1 second between them:
for i in {1..3}; do date; sleep 1; done
Example executing this and reading its output line-by-line:
cmd := exec.Command("bash", "-c", "for i in {1..3}; do date; sleep 1; done")
out, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
defer out.Close()
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
scanner := bufio.NewScanner(out)
for scanner.Scan() {
line := scanner.Text()
fmt.Println("Output:", line)
}
Example output:
2022/11/29 14:38:48 Output: Tue Nov 29 02:38:48 PM CET 2022
2022/11/29 14:38:49 Output: Tue Nov 29 02:38:49 PM CET 2022
2022/11/29 14:38:50 Output: Tue Nov 29 02:38:50 PM CET 2022
(The first date-time at the beginning of each line is from the log
package, to verify each line is printed after a second delay, the other timestamp is the output of the date
command.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论