当退出代码不为零时,Golang exec.Command返回nil错误

I'm trying to run a command in Golang, but it looks like it loses the exit code because the err is nil:

func runCommand() []byte, error {
  cmd := exec.Command("/bin/bash", "-c", "KUBECONFIG=/tmp/.kube/config helm version")

  cmd.Stdin = os.Stdin
  cmd.Stderr = os.Stderr

  stdOut, err := cmd.StdoutPipe()
  if err != nil {
      return nil, err
  }

  if err := cmd.Start(); err != nil {
      return nil, err
  }

  bytes, err := ioutil.ReadAll(stdOut)
  if err != nil {
      return nil, err
  }
  if err := cmd.Wait(); err != nil {
      return nil, err
  }

  fmt.Println(string(bytes))

  return bytes, nil
}

This return nil, even though the command returns with exit code != 0.

If I type:

$> /bin/bash -c KUBECONFIG=/tmp/.kube/config helm version
$<
$> echo $?
$< 0

If I type:

$> /bin/bash -c 'KUBECONFIG=/tmp/.kube/config helm version'
$< ...connection refused
$> echo $?
$< 1

So I tried to wrap the command in single quote:

cmd := exec.Command("/bin/bash", "-c", "'KUBECONFIG=/tmp/.kube/config helm version'")

but then I get:

/bin/bash: KUBECONFIG=/tmp/.kube/config helm version: No such file or directory

(needless to say that /tmp/.kube/config is there, but I don't think the no such file or directory refers to that anyway).

What am I doing wrong?

Thanks

UPDATE: turns out I got it wrong. In fact I had two commands attempted and for some reason I was sure the one failing was the one I mentioned above, when instead the second command was exiting with a status code different from 0. The code works as expected and the err is not nil in case of exit code != 0. Sorry about that.

doufen3563
doufen3563 感谢您的评论。我已经更新了原始问题。确实这不是问题。如果该命令以退出状态!=0终止,则代码返回err!=nil。我有两个命令一个接一个地运行,并且困惑于哪个命令应该返回err!=nil。抱歉
大约一年之前 回复
du9698
du9698 仔细研究一下,您没有检查命令中的错误,那么您如何知道它没有返回非零退出状态?问题实际上是关于设置环境变量的吗?直接在执行环境中设置它们比处理shell解析要容易得多(再次,如果根本不使用bash-c,控制发生的事情要容易得多)
大约一年之前 回复
duanjigua5753
duanjigua5753 JimB,原因是我不必拆分命令中的所有参数,而且我有一些带有管道的命令,这些管道我不知道如何在Go中执行。如果我在bash中使用引号来运行该bash-c命令,则退出状态将继续。如何从Go中实现?
大约一年之前 回复
douxuan1284
douxuan1284 您正在运行的命令是bash,并且以0退出。为什么不直接运行helm?
大约一年之前 回复

1个回答



似乎您应该可以通过 exec.ExitError </ code>来获取它,请参见 exec程序包。 请注意,您可能需要Go 1.12。 这是一个可运行的示例(但在去游乐场时不会给您真实的输出):</ p>

  package main 

import(
“ fmt”
“ io / ioutil“
” os“
” os / exec“

func main(){
cmd:= exec.Command(/ bin / bash-cFOO = bar ls / foo
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
stdOut,err:= cmd.StdoutPipe()
if err!= nil {
fmt.Println( “错误1”)
}
如果err:= cmd.Start(); err!= nil {
fmt.Println(“错误2”)
}
字节,如果err!= nil {
fmt.Println(“错误3”),则err:= ioutil.ReadAll(stdOut)

}
如果err:= cmd.Wait(); err!= nil {
fmt.Println(“ Error 4”)
如果exitError,确定:= err。(* exec.ExitError); ok {
fmt.Printf(“退出代码为%d
”,exitError.ExitCode())
}
}
fmt.Println(string(bytes))
}
</ code> </ pre>

在我的系统上打印:</ p>

  $请运行main.go 
ls:无法访问“ / foo”:没有此类文件 或目录
错误4
退出代码为2
</ code> </ pre>

如果这对您不起作用,也许值得遵循@JimB的建议并直接调用Helm? Go标准库也应该支持管道:</ p>


它包装了os.StartProcess,以便更轻松地重新映射stdin和stdout,将I / O与管道连接以及执行 其他调整。</ p>
</ blockquote>

exec包< / a>)</ p>
</ div>

展开原文

原文

Seems like you should be able to get it with exec.ExitError, see exec package. Note that you may need Go 1.12. Here's a runnable example (but it won't give you realistic output at the go playground):

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "os/exec"
)

func main() {
    cmd := exec.Command(`/bin/bash`, `-c`, `FOO=bar ls /foo`)
    cmd.Stdin = os.Stdin
    cmd.Stderr = os.Stderr
    stdOut, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println("Error 1")
    }
    if err := cmd.Start(); err != nil {
        fmt.Println("Error 2")
    }
    bytes, err := ioutil.ReadAll(stdOut)
    if err != nil {
        fmt.Println("Error 3")
    }
    if err := cmd.Wait(); err != nil {
        fmt.Println("Error 4")
        if exitError, ok := err.(*exec.ExitError); ok {
            fmt.Printf("Exit code is %d
", exitError.ExitCode())
        }
    }
    fmt.Println(string(bytes))
}

On my system that prints:

$ go run main.go
ls: cannot access '/foo': No such file or directory
Error 4
Exit code is 2

If that doesn't work for you, maybe it's worth following @JimB's suggestion and invoking helm directly? The Go standard library should support pipes as well:

It wraps os.StartProcess to make it easier to remap stdin and stdout, connect I/O with pipes, and do other adjustments.

(exec package)

duanlaican1849
duanlaican1849 将问题更新为不是实际问题,但是接受了此答案,因为您提供了检查退出代码的代码。 谢谢
大约一年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问