Прокси 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
Другие вопросы по тегам