@@ 47,6 47,7 @@ import (
"errors"
"fmt"
"io"
+ "os"
"os/exec"
"sync"
"syscall"
@@ 94,6 95,8 @@ type Cmd struct {
stderrBuf *OutputBuffer
stdoutStream *OutputStream
stderrStream *OutputStream
+ stdoutFile *os.File
+ stderrFile *os.File
status Status
statusChan chan Status // nil until Start() called
doneChan chan struct{} // closed when done running
@@ 153,6 156,9 @@ type Options struct {
// streaming channels, else lines are dropped silently.
Streaming bool
+ // If File is set, Cmd.Stdout and Cmd.Stderr are written directly to it.
+ File *os.File
+
// BeforeExec is a list of functions called immediately before starting
// the real command. These functions can be used to customize the underlying
// os/exec.Cmd. For example, to set SysProcAttr.
@@ 203,6 209,11 @@ func NewCmdOptions(options Options, name string, args ...string) *Cmd {
c.stderrStream.SetLineBufferSize(int(options.LineBufferSize))
}
+ if options.File != nil {
+ c.stdoutFile = options.File
+ c.stderrFile = options.File
+ }
+
if len(options.BeforeExec) > 0 {
c.beforeExecFuncs = []func(cmd *exec.Cmd){}
for _, f := range options.BeforeExec {
@@ 409,7 420,7 @@ func (c *Cmd) run(in io.Reader) {
// Set exec.Cmd.Stdout and .Stderr to our concurrent-safe stdout/stderr
// buffer, stream both, or neither
switch {
- case c.stdoutBuf != nil && c.stdoutStream != nil: // buffer and stream
+ case c.stdoutBuf != nil && c.stdoutStream != nil && c.stdoutFile != nil: // buffer and stream
cmd.Stdout = io.MultiWriter(c.stdoutStream, c.stdoutBuf)
cmd.Stderr = io.MultiWriter(c.stderrStream, c.stderrBuf)
case c.stdoutBuf != nil: // buffer only
@@ 418,6 429,9 @@ func (c *Cmd) run(in io.Reader) {
case c.stdoutStream != nil: // stream only
cmd.Stdout = c.stdoutStream
cmd.Stderr = c.stderrStream
+ case c.stdoutFile != nil: // file only
+ cmd.Stdout = c.stdoutFile
+ cmd.Stderr = c.stderrFile
default: // no output (cmd >/dev/null 2>&1)
cmd.Stdout = nil
cmd.Stderr = nil