dousu5608 2019-07-14 20:28
浏览 160
已采纳

当退出代码不为零时,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.

  • 写回答

1条回答 默认 最新

  • doushi9376 2019-07-14 23:04
    关注

    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)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置