Failure to write output of shell command to file in Go -


i have written following function executing snt2cooc command (one of preprocessing steps running giza++. our purposes think can consider snt2cooc script black box):

func snttocooc(srcvocab, tgtvocab, sntpath, outpath string) error {     // open out file writing     outfile, err := os.create(outpath)     if err != nil {         return err     }     defer outfile.close()      cmdstr := "snt2cooc"     args := []string{srcvocab, tgtvocab, sntpath}     cmd := exec.command(cmdstr, args...)     cmd.stdout = outfile     if err = cmd.run(); err != nil {         return err     }     cmd.wait()     return err } 

when running, function executes without error, output file empty. same code works other similar commands, not specific snt2cooc command, , noticed when run command in shell directly:

snt2cooc file1.vcb file2.vcb file3.snt

i following output:

end. 0 2 0 3 0 4 0 5 0 6 

(truncated brevity)

and if send output of command file directly shell:

snt2cooc file1.vcb file2.vcb file3.snt > out.txt 

the contents of out.txt expected:

0 2 0 3 0 4 0 5 0 6 

notice how in first case, line end. output stdout first, , real output of command sent stdout. therefore think there race condition going on, go code finishes executing before command's final output written file. despite calling cmd.wait(). i'm not sure snt2cooc command doing internally. provide hint on how solve this?

edit 1:

it seems following code, sleep of 500ms included, consistently writes output file snt2cooc command:

cmdstr := "snt2cooc" args := []string{srcvocab, tgtvocab, sntpath} cmd := exec.command(cmdstr, args...) stdout, err := cmd.stdoutpipe() time.sleep(500 * time.millisecond) if err != nil {     return err } err = cmd.start() if err != nil {     return err }  out := bufio.newscanner(stdout) out.scan() {     outfile.write(out.bytes())     outfile.writestring("\n") } if err := out.err(); err != nil {     return err } 

this proves me there race condition going on, go program exiting before output written file. added bounty question, hope can 1) explain why happening , 2) provide non-hacky way (i.e. 500ms sleep) fix it.

first, clean code.

cmd.stderr = os.devnull, ignore stderr. stdout , stderr specify process's standard output , error. if either nil, run connects corresponding file descriptor null device (os.devnull).

cmd.wait() returns error, ignore it. func (c *cmd) wait() error.

wait waits command exit. must have been started start. use run, not start.

what output when run code?

failure.go:

package main  import (     "fmt"     "os"     "os/exec" )  func main() {     err := snttocooc("file1.vcb", "file2.vcb", "file3.snt", "out.txt")     if err != nil {         fmt.println(err)     } }  func snttocooc(srcvocab, tgtvocab, sntpath, outpath string) error {     outfile, err := os.create(outpath)     if err != nil {         return err     }     defer outfile.close()     cmdstr := "snt2cooc"     args := []string{srcvocab, tgtvocab, sntpath}     cmd := exec.command(cmdstr, args...)     cmd.stdout = outfile     cmd.stderr = os.stderr     err = cmd.run()     if err != nil {         return err     }     return err } 

run:

$ rm -f out.txt && go run failure.go && cat out.txt 

also, output when run code cmd.stdout = os.stdout substituting cmd.stdout = outfile.


Comments