Problem with exec.Command and multiple writes to cmd.Stdin

1,326 views
Skip to first unread message

da...@synergetic-data.com

unread,
Aug 27, 2013, 4:51:11 PM8/27/13
to golan...@googlegroups.com
Hi folks,

I have only been using Go for about a month, so any help would be greatly appreciated.
I am working on a little application that uses the exec.Command to run an ssh process
to a remote host. Everything is working fine, up until the time the process that invokes
exec.Command tries to write back to the ssh process. There is no actual error that I can
find, but the receiving process reads 0 bytes. Here is an general description of what
is going on:

// On the sending host:
cmd := exec.Command("/usr/bin/ssh", "f...@192.168.1.100", "/some/program")
cmd.Stdin = strings.NewReader("Hello, how are you")

var remoteStdout bytes.Buffer    // A buffer to hold the remote command's stdout.
var remoteStderr bytes.Buffer    // A buffer to hold the remote command's stdout.
cmd.Stdout = &remoteStdout    // The remote command's stdout.
cmd.Stderr =  &remoteStderr    // The remote command's stderr.

err = cmd.Run()
response := remoteStdout
fmt.Fprintf(os.Stderr, "Response: %s\n", response)

cmd.Stdin = strings.NewReader("Ok, Goodbye")

// On the receiving host:
data, err := ioutil.ReadAll(os.Stdin)
fmt.Fprintf(os.Stderr, "Read %d bytes of type: %T from stdin\n", len(data), data)
os.Stdout.WriteString("Hello, I'm fine, thanks.")
data, err := ioutil.ReadAll(os.Stdin)

At which point the receiver reports that it has read 0 bytes.

I have read the documentation, searched for examples, googled up and down until I've read
most everything found, without any luck. Any help would be greatly appreciated. I am really
enjoying working with Go.

Best Regards,

Daryl


Brad Fitzpatrick

unread,
Aug 27, 2013, 7:54:43 PM8/27/13
to da...@synergetic-data.com, golang-nuts
Is this pseudo code?  This wouldn't compile... you would get "no new variables on left side of :=" for the second call to ioutil.ReadAll(os.Stdin).  (why are you doing that?)

If you read until EOF, any future read will also be EOF.



--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jesse McNelis

unread,
Aug 27, 2013, 8:05:34 PM8/27/13
to da...@synergetic-data.com, golang-nuts
On Wed, Aug 28, 2013 at 6:51 AM, <da...@synergetic-data.com> wrote:
Hi folks,

I have only been using Go for about a month, so any help would be greatly appreciated.
I am working on a little application that uses the exec.Command to run an ssh process
to a remote host. Everything is working fine, up until the time the process that invokes
exec.Command tries to write back to the ssh process. There is no actual error that I can
find, but the receiving process reads 0 bytes. Here is an general description of what
is going on:

// On the sending host:
cmd := exec.Command("/usr/bin/ssh", "f...@192.168.1.100", "/some/program")
cmd.Stdin = strings.NewReader("Hello, how are you")

var remoteStdout bytes.Buffer    // A buffer to hold the remote command's stdout.
var remoteStderr bytes.Buffer    // A buffer to hold the remote command's stdout.
cmd.Stdout = &remoteStdout    // The remote command's stdout.
cmd.Stderr =  &remoteStderr    // The remote command's stderr.

err = cmd.Run() 
 
Did you check this error value?

response := remoteStdout
 
Why the assignment to 'response'? Do you realise you're making a copy of the bytes.Buffer?
It shouldn't matter here because you already wrote to it, but it's unnecessary and could create confusion later.
 
fmt.Fprintf(os.Stderr, "Response: %s\n", response)

cmd.Stdin = strings.NewReader("Ok, Goodbye")

This doesn't make sense here. The command already ran, I don't see why you'd assign a different Stdin to it.
 

// On the receiving host:
data, err := ioutil.ReadAll(os.Stdin)
fmt.Fprintf(os.Stderr, "Read %d bytes of type: %T from stdin\n", len(data), data)
os.Stdout.WriteString("Hello, I'm fine, thanks.")
data, err := ioutil.ReadAll(os.Stdin)

I'm going to have to assume you're checking all these error return values, because you said "There is no actual error that I can
find". If you're not then you should.

At which point the receiver reports that it has read 0 bytes.

I have read the documentation, searched for examples, googled up and down until I've read
most everything found, without any luck. Any help would be greatly appreciated. I am really
enjoying working with Go.

You should give a complete runnable example. This code looks like it should work, but there is obviously things missing and those things could be the problem.


Daryl Williams

unread,
Aug 27, 2013, 8:08:43 PM8/27/13
to golan...@googlegroups.com
Hi Brad, Thanks for your reply. Yes it is pseudo code, sorry if I did not make that obvious. Thanks for pointing out about the "no new variables on left side of :=" but that is not the real problem (I should have been more careful with my pasting). The problem I am trying to understand is why I am unable to read from stdin a second time. I need to have a "send, response send, response" sequence where the initiating process sends some data, gets a response from the remote host and then sends the remote host some more data, much like an SMTP or similar protocol conversation. From what you said about EOF I gather this may not be doable in Go?

Thanks again for your reply.

Regards,

Daryl

Brad Fitzpatrick

unread,
Aug 27, 2013, 8:17:25 PM8/27/13
to Daryl Williams, golang-nuts
It won't work in any language.

Once you hit EOF, that's the End.

You shouldn't be using ioutil.ReadAll because your records aren't separated by EOFs.  They're separated by either newlines (use bufio.NewScanner) or size (use io.ReadFull)



Daryl Williams

unread,
Aug 27, 2013, 8:19:36 PM8/27/13
to golan...@googlegroups.com
Hi Jesse, Thanks for your reply. Yes I am checking the error returned by the cmd.Run method, I just left it out
of my example code to make it more succinct. The reason I made the "response := remoteStdout" was so I could
parse the response, but I guess it is rather redunant and I could have just acted on remoteStdout instead. As to
the 'cmd.Stdin = strings.NewReader("Ok, Goodbye")' because the command already ran, both processes are still
running and printing to the screen, the problem is that I am unable to write back to finish the conversation.

If I can provide more detail please let me know.

Thanks,

Daryl



On Tuesday, August 27, 2013 1:51:11 PM UTC-7, Daryl Williams wrote:

Jesse McNelis

unread,
Aug 27, 2013, 8:24:28 PM8/27/13
to Daryl Williams, golang-nuts
On Wed, Aug 28, 2013 at 10:19 AM, Daryl Williams <da...@synergetic-data.com> wrote:
Hi Jesse, Thanks for your reply. Yes I am checking the error returned by the cmd.Run method, I just left it out
of my example code to make it more succinct. The reason I made the "response := remoteStdout" was so I could
parse the response, but I guess it is rather redunant and I could have just acted on remoteStdout instead. As to
the 'cmd.Stdin = strings.NewReader("Ok, Goodbye")' because the command already ran, both processes are still
running and printing to the screen, the problem is that I am unable to write back to finish the conversation.

"Run starts the specified command and waits for it to complete."
The program has finished running when the cmd.Run() method returns.

But also, the program was given an io.Reader when it started and you can't change what that io.Reader is while it's running.
What you can do is use a pipe to communicate with the process.


Daryl Williams

unread,
Aug 28, 2013, 12:30:07 PM8/28/13
to golan...@googlegroups.com
Hi guys, I appreciate your replies. Brad thanks for pointing out the problem with ioutil.ReadAll, I should have read the documentation with more care (mea culpa). I believe the problem, as you both pointed out, is with the read function reaching EOF. Jesse thanks for suggesting I use a pipe. I guess I had assumed that was what the exec.Command was doing under the covers, but again, I should have read the documentation more carefully. I will now try using a Cmd.StdinPipe and see how that works.

Thanks again for your help.

Best Regards,

Daryl


On Tuesday, August 27, 2013 1:51:11 PM UTC-7, Daryl Williams wrote:
Reply all
Reply to author
Forward
0 new messages