I've got the following code that executes an arbitrary shell command and pipes the stdout and stderr to the terminal.:
c := exec.Command("/bin/sh", "-c", cmd)
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
However, I need to process the output before I print it, so I've wrapped it with a proxy io.Writer interface:
type ProxyWriter struct {
file *os.File
}
func NewProxyWriter(file *os.File) *ProxyWriter {
return &ProxyWriter{
file: file,
}
}
func (w *ProxyWriter) Write(p []byte) (int, error) {
// ... do something with bytes first
fmt.Fprintf(w.file, "%s", string(p))
return len(p), nil
}
So the original code is now:
c := exec.Command("/bin/sh", "-c", cmd)
c.Stdin = os.Stdin
c.Stdout = NewProxyWriter(os.Stdout)
c.Stderr = NewProxyWriter(os.Stderr)
This works for the most part, however, stdout and stderr no longer seem to qualify as a TTY. Any previously styled or colored output is no longer styled or colored.
I've confirmed that this is not an issue of my ProxyWriter simply messing with the formatting by setting the command to the following, which outputs the colored text correctly.
c := exec.Command("echo", "\033[0;31mTEST\033[0m")
A more explicit test is:
c := exec.Command("/bin/sh", "-c", "if [ -t 1 ] ; then echo \"terminal\"; else echo \"not a terminal\"; fi")
Which outputs:
not a terminal
Is there anyway I can wrap the commands stdout / stderr without losing the TTY status?
Replace
func (w *ProxyWriter) Write(p []byte) (int, error) {
// ... do something with bytes first
fmt.Fprintf(w.file, "%s", string(p))
return len(p), nil
}
To
func (w *ProxyWriter) Write(p []byte) (int, error) {
return w.Write(p)
}
fmt.Fprintf have some logic to avoid terminal breaking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With