Прокси exec.Cmd Stdout / Stderr без потери TTY
У меня есть следующий код, который выполняет произвольную команду оболочки и передает stdout
а также stderr
до терминала.:
c := exec.Command("/bin/sh", "-c", cmd)
c.Stdin = os.Stdin
c.Stdout = os.Stdout
c.Stderr = os.Stderr
Однако мне нужно обработать вывод перед печатью, поэтому я обернул его прокси-интерфейсом io.Writer:
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
}
Итак, оригинальный код сейчас:
c := exec.Command("/bin/sh", "-c", cmd)
c.Stdin = os.Stdin
c.Stdout = NewProxyWriter(os.Stdout)
c.Stderr = NewProxyWriter(os.Stderr)
Это работает по большей части, однако, stdout
а также stderr
кажется, больше не квалифицируется как TTY. Любой ранее стилизованный или цветной вывод больше не стилизован и не окрашен.
Я подтвердил, что это не проблема моего ProxyWriter
просто возиться с форматированием, задав следующую команду, которая правильно выводит цветной текст.
c := exec.Command("echo", "\033[0;31mTEST\033[0m")
Более явный тест:
c := exec.Command("/bin/sh", "-c", "if [ -t 1 ] ; then echo \"terminal\"; else echo \"not a terminal\"; fi")
Какие выводы:
not a terminal
Можно ли как-нибудь обернуть команды stdout / stderr без потери статуса TTY?
2 ответа
Замещать
func (w *ProxyWriter) Write(p []byte) (int, error) {
// ... do something with bytes first
fmt.Fprintf(w.file, "%s", string(p))
return len(p), nil
}
к
func (w *ProxyWriter) Write(p []byte) (int, error) {
return w.Write(p)
}
fmt.Fprintf
иметь некоторую логику, чтобы избежать взлома терминала.
Вам понадобится полная реализация tty, чтобы искусственный стандартный вывод квалифицировался как терминал. Библиотека, предложенная mattn, кажется хорошим кандидатом.
Однако в зависимости от команды, для которой вы пытаетесь сохранить раскрашивание, может быть доступен другой гораздо более простой вариант. Большинство утилит GNU с цветным выводом, таких как
ls
,
grep
, а также
dmesg
есть
--color
флаг, который может отменить обнаружение TTY.
Например:
$ ls --color=always
$ ls -lsh | grep --color=always drwx
Я часто использую это для передачи цветного вывода dmesg через less, чтобы я мог разбить его на страницы:
$ sudo dmesg --color=always | less -R
Вы также можете сделать наоборот и отключить вывод цвета:
ls --color=never