为什么我使用stderr和ioutil.ReadAll在这个Go程序中获得“错误的文件描述符”

时间:2013-11-21 23:29:04

标签: go stdout stderr

命令“psql”应该抛出错误,我正在尝试读取stderr并在Go程序中打印它。我使用ioutil.ReadAll从stderr和stdout读取数据。

不幸的是,它根本不是从stderr读取的。 ioutil.ReadAll返回一个错误,这不是我期待的错误。

我得到的错误是

read |0: bad file descriptor

这是代码。

package main

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

func main() {
        cmd := exec.Command("psql")
        stdout, err := cmd.StdoutPipe()
        if err != nil {
                fmt.Printf("Error: %s", err)
        }
        stderr, err := cmd.StderrPipe()
        if err != nil {
                fmt.Printf("Error: %s", err)
        }
        err = cmd.Start()
        if err != nil {
                fmt.Printf("Start error %s",err)
        }

        d := cmd.Wait()
        if d != nil {
                fmt.Println(d)
        }

        stdo,g := ioutil.ReadAll(stdout)
        stde,f := ioutil.ReadAll(stderr)

        if g != nil {
                fmt.Println(g)
        }

        if f !=nil {
                fmt.Println(f)
        }

        fmt.Printf("Standard err is %s \n", stde)
        fmt.Printf("Standard out is %s \n",stdo)
}

1 个答案:

答案 0 :(得分:10)

我发现通过实验我得到了错误,因为我正在调用

   stdo,g := ioutil.ReadAll(stdout)
   stde,f := ioutil.ReadAll(stderr)

 d := cmd.Wait()

所以会发生什么是stdout,stderr管道在cmd.Wait()返回后关闭。

以下是cmd.StderrPipe()

的代码注释
// StderrPipe returns a pipe that will be connected to the command's
// standard error when the command starts.
// The pipe will be closed automatically after Wait sees the command exit.

很明显,我们无法在关闭后阅读stdout和stderr。

在命令启动之前我们无法读取它们。所以我们必须把它们放在开始和等待之间。

以下是修复该问题的代码。

package main

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

func main() {
        cmd := exec.Command("psql")
        stdout, err := cmd.StdoutPipe()
        if err != nil {
                fmt.Printf("Error: %s", err)
        }
        stderr, err := cmd.StderrPipe()
        if err != nil {
                fmt.Printf("Error: %s", err)
        }
        err = cmd.Start()
        if err != nil {
                fmt.Printf("Start error %s",err)
        }

        stdo,g := ioutil.ReadAll(stdout)
        stde,f := ioutil.ReadAll(stderr)

        d := cmd.Wait()

        if d != nil {
                fmt.Println(d)
        }

        if g != nil {
                fmt.Println(g)
        }

        if f !=nil {
                fmt.Println(f)
        }

        fmt.Printf("Standard err is %s \n", stde)
        fmt.Printf("Standard out is %s \n",stdo)
}