Как отладить ошибку выхода 1 при запуске exec.Command в Golang

Когда я запускаю код ниже:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
    fmt.Println(err)
    return
}
fmt.Println("Result: " + out.String())

Я получаю эту ошибку:

статус выхода 1

Однако это бесполезно для отладки точной причины ошибки.

Как получить более подробную информацию?


person laurent    schedule 10.08.2013    source источник


Ответы (2)


Решение состоит в использовании свойства Stderr объекта Command. Это можно сделать следующим образом:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
    fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
    return
}
fmt.Println("Result: " + out.String())

Выполнение приведенного выше кода прояснит, в чем проблема:

статус выхода 1: найти: -exec: без завершения ";" или "+"

Изменить:

В приведенном выше коде мы ожидаем, что в случае ошибки сообщения будут напечатаны в stderr, и команда вернет ненулевой код ошибки. Это более или менее стандартно.

Однако, как упоминалось ниже @snorberhuis, некоторые команды выводят ошибки на стандартный вывод. Другие команды могут печатать в stderr, но возвращать код ошибки 0 (в этом случае err будет nil). И наличие сообщений в stderr не обязательно означает наличие ошибки (инструменты ffmpeg часто делают это).

Таким образом, в основном вам может потребоваться настроить приведенный выше код, чтобы он соответствовал командам, которые вы ожидаете.

person laurent    schedule 10.08.2013
comment
Ваше решение очень полезно для отладки, но мне пришлось внести небольшое изменение, чтобы увидеть результат. Я отлаживал команду завершения работы Windows также со статусом выхода 1. Это печатает Stdout. Поэтому я переместил последнюю строку над оператором if. - person snorberhuis; 24.10.2016
comment
Это решение лучше, чем CombinedOutput(), так как здесь мы получаем подробный текст ошибки (из cmd.Stderr). В output, err := cmd.CombinedOutput() output содержит текст ошибки, но он такой же, как err. - person fiberair; 24.11.2017

Как упомянул Лоран, вы можете переопределить дескриптор файла Stderr, чтобы захватить вывод stderr для лучшего сообщения об ошибке. Я лично предпочитаю использовать метод CombinedOutput для команды, если делаю что-то относительно простое:

cmd := exec.Command("find", "/", "-maxdepth", "1", "-exec", "wc", "-c", "{}", "\\")
output, err := cmd.CombinedOutput()
if err != nil {
    fmt.Println(fmt.Sprint(err) + ": " + string(output))
    return
}
fmt.Println(string(output))

Вот ссылка play.golang.org для приведенного выше примера: http://play.golang.org/p/z8k9zO755P

person noj    schedule 11.08.2013
comment
Этот ответ более элегантный; D - person Qinsi; 18.06.2020
comment
Идеальный ответ :) - person Sathish Kumar; 04.02.2021