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

为什么我会得到;“错误的文件描述符”;在这个Go程序中,使用stderr和ioutil.ReadAll,go,stdout,stderr,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" )

命令“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)
}

我发现,通过实验,我得到了错误,因为我打电话

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

因此,在
cmd.Wait()
返回后,stdout、stderr管道就会关闭

以下是
cmd.StderrPipe()的代码注释

所以很明显,我们不能在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)
}

请注意,立即处理错误通常是一个好主意。在您的示例中,如果
ioutil.ReadAll(stdout)
失败,则在处理错误之前将调用
ioutil.ReadAll(stderr)
cmd.Wait()
// 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.
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)
}