Почему я получаю "плохой файловый дескриптор" в этой программе Go, используя stderr и ioutil.ReadAll

команда "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 ответов


я обнаружил, что путем экспериментов я получаю ошибку, из-за того, что я вызываю

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