Repository: benhoyt/goawk (go)

Issue:
Wrong order of output with pipe and print
Hi!

```awk
# delme.awk
BEGIN {
  print "222" | (cmd = "cat")
  close(cmd)
  print "DONE"
}
```

```
$ gawk -f delme.awk 
222
DONE

$ mawk -f delme.awk 
222
DONE

$ ./soft/bwk -f delme.awk 
222
DONE

$ ./soft/goawk1.23.1 -f delme.awk 
DONE
222
```

Pull request description:
Wait for command to finish when a pipe is closed
Fixes #182

Patch:
diff --git a/interp/io.go b/interp/io.go
index bda14ca..9d19761 100644
--- a/interp/io.go
+++ b/interp/io.go
@@ -97,8 +97,8 @@ func (p *interp) writeCSV(output io.Writer, fields []string) error {
 	return nil
 }
 
-// Implement a buffered version of WriteCloser so output is buffered
-// when redirecting to a file (eg: print >"out")
+// Buffered version of WriteCloser so output is buffered when redirecting to a
+// file (eg: print >"out")
 type bufferedWriteCloser struct {
 	*bufio.Writer
 	io.Closer
@@ -117,6 +117,31 @@ func (wc *bufferedWriteCloser) Close() error {
 	return wc.Closer.Close()
 }
 
+// Buffered version of WriteCloser for pipes so output is buffered when
+// redirecting to a command; waits for the command to finish on close.
+type commandWriteCloser struct {
+	*bufio.Writer
+	io.Closer
+	command *exec.Cmd
+}
+
+func newCommandWriteCloser(w io.WriteCloser, command *exec.Cmd) *commandWriteCloser {
+	writer := bufio.NewWriterSize(w, outputBufSize)
+	return &commandWriteCloser{writer, w, command}
+}
+
+func (wc *commandWriteCloser) Close() error {
+	err := wc.Writer.Flush()
+	if err != nil {
+		return err
+	}
+	err = wc.Closer.Close()
+	if err != nil {
+		return err
+	}
+	return wc.command.Wait()
+}
+
 // Determine the output stream for given redirect token and
 // destination (file or pipe name)
 func (p *interp) getOutputStream(redirect Token, destValue value) (io.Writer, error) {
@@ -172,7 +197,7 @@ func (p *interp) getOutputStream(redirect Token, destValue value) (io.Writer, er
 			return ioutil.Discard, nil
 		}
 		p.commands[name] = cmd
-		buffered := newBufferedWriteCloser(w)
+		buffered := newCommandWriteCloser(w, cmd)
 		p.outputStreams[name] = buffered
 		return buffered, nil
 


Test patch:
diff --git a/interp/interp_test.go b/interp/interp_test.go
index f429023..cac7892 100644
--- a/interp/interp_test.go
+++ b/interp/interp_test.go
@@ -827,6 +827,7 @@ BEGIN { x[1]=3; f5(x); print x[1] }
 	getline <"out"
 	print $0
 }`, "", "foo\nbar\n", "", ""},
+	{`BEGIN { print "x" | "cat"; close("cat"); print "y" }`, "", "x\ny\n", "", ""},
 
 	// Ensure data returned by getline (in various forms) is treated as numeric string
 	{`BEGIN { getline; print($0==0) }`, "0.0", "1\n", "", ""},