【问题标题】:Why do I get "bad file descriptor" in this Go Program using stderr and ioutil.ReadAll为什么我在这个 Go 程序中使用 stderr 和 ioutil.ReadAll 得到“错误的文件描述符”
【发布时间】:2013-11-21 23:29:03
【问题描述】:

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

【问题讨论】:

    标签: go stdout stderr


    【解决方案1】:

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

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

    之后

     d := cmd.Wait()
    

    所以在cmd.Wait() 返回后,stdout、stderr 管道会关闭。

    这里是cmd.StderrPipe()的代码cmets

    // 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)
    }
    

    【讨论】:

    • 请注意,立即处理错误通常是个好主意。在您的示例中,如果 ioutil.ReadAll(stdout) 失败,则将在处理错误之前调用 ioutil.ReadAll(stderr)cmd.Wait()
    猜你喜欢
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 2016-11-25
    • 2017-09-18
    • 2022-01-19
    相关资源
    最近更新 更多