Skip to content

Instantly share code, notes, and snippets.

@mxschmitt
Last active April 18, 2024 21:48
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mxschmitt/6c07b5b97853f05455c3fdaf48b1a8b6 to your computer and use it in GitHub Desktop.
Save mxschmitt/6c07b5b97853f05455c3fdaf48b1a8b6 to your computer and use it in GitHub Desktop.
Golang example of cmd stderr / stdout merge to a single channel
@echo off
echo Stdout
echo Stderr 1>&2
package main
import (
"bufio"
"fmt"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("cmd.bat")
stderr, err := cmd.StderrPipe()
if err != nil {
log.Fatalf("could not get stderr pipe: %v", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatalf("could not get stdout pipe: %v", err)
}
go func() {
merged := io.MultiReader(stderr, stdout)
scanner := bufio.NewScanner(merged)
for scanner.Scan() {
msg := scanner.Text()
fmt.Printf("msg: %s\n", msg)
}
}()
if err := cmd.Run(); err != nil {
log.Fatalf("could not run cmd: %v", err)
}
if err != nil {
log.Fatalf("could not wait for cmd: %v", err)
}
}
@pzghost
Copy link

pzghost commented Nov 9, 2020

package main

import (
	"fmt"
	"os/exec"
)

func main() {

	cmd := exec.Command("/bin/bash", "-c", "ls /")
	res, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(res))
		panic(err)
	}

	fmt.Println(string(res))
	cmd = exec.Command("/bin/bash", "-c", "ls /notfile")
	res, err = cmd.CombinedOutput()
	if err != nil {
		fmt.Println(string(res))
		panic(err)
	}
	fmt.Println(string(res))
}

the output:

bin
boot
dev
etc
go
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

ls: cannot access /notfile: No such file or directory

panic: exit status 2

goroutine 1 [running]:
main.main()
	/tmp/t.go:22 +0x3c7
exit status 2

@watsoncj
Copy link

watsoncj commented Dec 15, 2021

Thanks for sharing this. Note that the implementation of io.MultiReader will not read from the second reader until the first reader is exhausted. As a result this approach is more of a concat than a merge.

https://go.dev/src/io/multi.go

To merge while maintaining write order, it’s possible to reassign.

cmdReader, err := cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout

https://stackoverflow.com/a/35995372

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment