Перенаправить stdout-канал дочернего процесса в Go
Я пишу программу в Go, которая выполняет сервер, такой как программа (также Go). Теперь я хочу иметь stdout дочерней программы в моем окне терминала, где я начал родительскую программу. Один из способов сделать это - с помощью функции cmd.Output()
, но это печатает stdout только после выхода процесса. (Это проблема, потому что эта серверная программа работает в течение длительного времени, и я хочу прочитать вывод журнала)
Переменная out
имеет значение type io.ReadCloser
, и я не знаю, что мне делать с ней для достижения моей задачи, и я не могу найти что-либо полезное в Интернете по этой теме.
func main() {
cmd := exec.Command("/path/to/my/child/program")
out, err := cmd.StdoutPipe()
if err != nil {
fmt.Println(err)
}
err = cmd.Start()
if err != nil {
fmt.Println(err)
}
//fmt.Println(out)
cmd.Wait()
}
Пояснение к коду: раскомментируйте функцию Println
, чтобы получить код для компиляции, я знаю, что Println(out io.ReadCloser)
не является значимой функцией.
(он выводит вывод &{3 |0 <nil> 0}
). Эти две строки необходимы для компиляции кода.
Ответы
Ответ 1
Теперь я хочу, чтобы stdout дочерней программы в моем терминале где я начал родительскую программу.
Не нужно возиться с трубами или гортанами, это легко.
func main() {
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
Ответ 2
Я считаю, что если вы импортируете io
и os
и замените это:
//fmt.Println(out)
с этим:
go io.Copy(os.Stdout, out)
(см. документацию для io.Copy
и для os.Stdout
), она будет делать то, что вы хотеть. (Отказ от ответственности: не проверен.)
Кстати, вы, вероятно, захотите также записать стандартную ошибку, используя тот же подход, что и для стандартного вывода, но с cmd.StderrPipe
и os.Stderr
.
Ответ 3
Для тех, кому это не нужно в цикле, но хотелось бы, чтобы команда выводила эхо в терминал, не имея cmd.Wait()
блокировки других операторов:
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
)
func checkError(err error) {
if err != nil {
log.Fatalf("Error: %s", err)
}
}
func main() {
// Replace `ls` (and its arguments) with something more interesting
cmd := exec.Command("ls", "-l")
// Create stdout, stderr streams of type io.Reader
stdout, err := cmd.StdoutPipe()
checkError(err)
stderr, err := cmd.StderrPipe()
checkError(err)
// Start command
err = cmd.Start()
checkError(err)
// Don't let main() exit before our command has finished running
defer cmd.Wait() // Doesn't block
// Non-blockingly echo command output to terminal
go io.Copy(os.Stdout, stdout)
go io.Copy(os.Stderr, stderr)
// I love Go trivial concurrency :-D
fmt.Printf("Do other stuff here! No need to wait.\n\n")
}