web-dev-qa-db-ja.com

Golangでexec.Commandを実行しているときに「exit status 1」エラーをデバッグする方法

以下のコードを実行すると:

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

ただし、これはエラーの正確な原因をデバッグするのに役立ちません。

より詳細な情報を取得する方法は?

35
laurent

解決策は、CommandオブジェクトのStderrプロパティを使用することです。これは次のように実行できます。

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が後述するように、一部のコマンドはエラーをstdoutに出力します。他のコマンドはstderrに出力されますが、エラーコード0を返します(この場合、errnilになります)。また、stderrにメッセージがあるということは、必ずしもエラーがあることを意味するわけではありません(ffmpegツールはこれを頻繁に行います)。

したがって、基本的には、期待するコマンドに対応するために上記のコードを微調整する必要があるかもしれません。

77
laurent

Laurentが述べたように、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

28
noj