Why am I getting a “bad file descriptor” in this Go program using stderr and ioutil.ReadAll

The psql command should throw an error, and I'm trying to read stderr and print it in a Go program. I use ioutil.ReadAll to read data from stderr and stdout.

Unfortunately, it does not read from stderr at all. ioutil.ReadAll returns an error that is not an expected error.

The error I get is

read |0: bad file descriptor 

Here is the code.

 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) } 
+7
go stdout stderr
source share
1 answer

I found that through an experiment that I get an error due to the fact that I'm calling

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

after

  d := cmd.Wait() 

so what happens when stdout, stderr pipe closes after cmd.Wait() returns.

Here are the code comments for 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. 

Thus, it is obvious that we cannot read stdout and stderr after they are closed.

We cannot read them before running the command. Therefore, we must put them between start and expectation.

Here is the code that fixes this.

 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) } 
+10
source share

All Articles