exec.Command vs. os.StartProcess

1,579 views
Skip to first unread message

Daryl Williams

unread,
Sep 11, 2013, 7:57:25 PM9/11/13
to golan...@googlegroups.com
Folks,

I have been using Cmd.Start() to execute a child process and that is working fine, but I have run into the requirement to be able to pass a variable number of arguments to the child process. As the exec.Command function does not appear to take an array or slice for the process arguments, I started playing with os.StartProcess(), which does take a string slice, and that also works well as long as I don't need to communicate with the child process. After reading up and studying the documentation I tried the following code:

// Parent process
rCmdIn, lCmdOut, err := os.Pipe() // Pipe to write from parent to remote child's stdin.
exitOnErr("1. os.Pipe(): ", err)
lCmdIn, rCmdOut, err := os.Pipe() // Pipe to read from remote cmd's stdout.
exitOnErr("2. os.Pipe(): ", err)

var procAttr os.ProcAttr
procAttr.Files = []*os.File{rCmdIn, rCmdOut, os.Stderr}
pid, err := os.StartProcess(ssh, args, &procAttr)
exitOnErr("os.StartProcess(): ", err)

data := make([]byte, 8) //Buffer to hold the length of data to follow.
_, err := io.ReadFull(lCmdIn, data)
exitOnErr("1. io.ReadFull(): ", err)
var size int64
buf := bytes.NewBuffer(data)
binary.Read(buf, binary.BigEndian, &size)
fmt.Printf("size: %d\n", size) // Prints the correct size.

data = make([]byte, size)
_, err = io.ReadFull(rCmdIn, data)
exitOnErr("2. io.ReadFull(): ", err) // Exits with error: read |0: resource temporarily unavailable

Hopefully this is pretty self explanatory. The first read works fine and gives me the size of the data to follow. The second read results in the error: read |0: resource temporarily unavailable. I should mention that the child is running as a remote process over ssh.

// Child process
err = binary.Write(os.Stdout, binary.BigEndian, int64(zbuf.Len())) // The zbuf contains some zlib compressed data.
exitOnErr("binary.Write(): ", err)
data := zbuf.Bytes()
sent, err := os.Stdout.Write(data)
exitOnErr("os.Stdout.Write(): ", err)
fmt.Printf("sent: %d\n", sent) // Prints the correct size of sent.


I am still pretty new to golang and probably doing something stupid, but any help would be greatly appreciated.

Thanks,

Daryl





Keith Rarick

unread,
Sep 11, 2013, 8:51:34 PM9/11/13
to Daryl Williams, golang-nuts
On Wed, Sep 11, 2013 at 4:57 PM, Daryl Williams
<da...@synergetic-data.com> wrote:
> I have run into the requirement to be able to pass a variable
> number of arguments to the child process. As the exec.Command function does
> not appear to take an array or slice for the process arguments,

Function exec.Command is variadic, for convenience when
the number of arguments is known at compile time. If you have
a slice of strings, you can apply it with the ... notation:

args := []string{"arg1", "arg2"}
cmd := exec.Command("echo", args...)

Daryl Williams

unread,
Sep 12, 2013, 1:57:27 PM9/12/13
to golan...@googlegroups.com
Hi Keith and Yiyus, Thanks for your replies, I seem to learn something new about go every day! Much appreciated.

Regards,

Daryl
Reply all
Reply to author
Forward
0 new messages