I use exec.Command("ssh", "user@addr") to create a system process, and use ExpectBatcher to send password expecting login automatically. However, this wouldn't work since the password promot comming neither from stdout nor stderr.
As said, OpenSSH client directly talks to /dev/tty which makes goexpect unable to receive any data from stdout/stderr, resulting in Expect not working.
This is not covered by current version, and it's pretty interesting to talk about.
Example code
package main
import (
"fmt"
"io"
"os"
"os/exec"
"syscall"
expect "github.com/google/goexpect"
)
func main() {
cmd := exec.Command("ssh", "localhost")
bs := []expect.Batcher{
&expect.BExpT{R: "password: ", T: 2},
&expect.BSnd{S: "some_password\n"},
}
pr1, pw1 := io.Pipe()
pr2, pw2 := io.Pipe()
cmd.Stdin, cmd.Stdout = pr1, pw2
err := cmd.Start()
if err != nil {
closeDescriptors(pr1, pw1, pr2, pw2)
panic(fmt.Sprintf("1: %s", err))
}
opt := &expect.GenOptions{
In: pw1,
Out: pr2,
Wait: func() error { return nil },
Close: func() error { return cmd.Process.Kill() },
Check: func() bool {
if cmd.Process == nil {
return false
}
// Sending Signal 0 to a process returns nil if
// process can take a signal , something else if not.
return cmd.Process.Signal(syscall.Signal(0)) == nil
},
}
exp, _, err := expect.SpawnGeneric(opt, -1, expect.Verbose(true), expect.VerboseWriter(os.Stdout))
if err != nil {
closeDescriptors(pr1, pw1, pr2, pw2)
panic(fmt.Sprintf("2: %s", err))
}
// not working since no data coming out from stdout/stderr
res, err := exp.ExpectBatch(bs, -1)
if err != nil {
panic(fmt.Sprintf("3: %s", err))
}
for _, item := range res {
fmt.Printf(">>> find res: %s\n", item.Output)
}
fmt.Println("done")
}
func closeDescriptors(closers ...io.Closer) {
for _, closer := range closers {
_ = closer.Close()
}
}
I use
exec.Command("ssh", "user@addr")
to create a system process, and useExpectBatcher
to send password expecting login automatically. However, this wouldn't work since the password promot comming neither from stdout nor stderr.As said, OpenSSH client directly talks to
/dev/tty
which makesgoexpect
unable to receive any data from stdout/stderr, resulting inExpect
not working.This is not covered by current version, and it's pretty interesting to talk about.
Example code