Is there a Interact() interface ?
cedarwu opened this issue · 2 comments
cedarwu commented
How to gives control of the child process to the interactive user (the human at the keyboard) like the interact method in expect/pexpect?
https://wiki.tcl-lang.org/page/interact
hinshun commented
Send os.Stdin
into the expect.Console
. This library is a bit lower level so we expect users to decide how to manage the IO and spawn the child processes.
cedarwu commented
Can't make the child shell work as normal, could you please give some advice?
The shell works, but completion and ctrl-c does not work.
Code as following:
First, make expect to login into another machine, then forward all signals to subprocess and wait for finish.
package main
import (
"log"
"os"
"os/exec"
"os/signal"
"syscall"
expect "github.com/Netflix/go-expect"
)
func main() {
c, err := expect.NewConsole(expect.WithStdout(os.Stdout), expect.WithStdin(os.Stdin))
if err != nil {
log.Fatal(err)
}
defer c.Close()
cmd := exec.Command("ssh", "root@ip", "-i", "~/.ssh/id_rsa")
cmd.Stdin = c.Tty()
cmd.Stdout = c.Tty()
cmd.Stderr = c.Tty()
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
_, err = c.ExpectString("[root@")
if err != nil {
log.Fatalln("expect err: [root@")
return
}
// wait for the command to finish
waitCh := make(chan error, 1)
go func() {
c.ExpectEOF()
waitCh <- cmd.Wait()
close(waitCh)
}()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan)
// You need a for loop to handle multiple signals
for {
select {
case sig := <-sigChan:
if err := cmd.Process.Signal(sig); err != nil {
log.Println("error sending signal", sig, err)
}
case err := <-waitCh:
log.Println("subprocess exited")
var waitStatus syscall.WaitStatus
if exitError, ok := err.(*exec.ExitError); ok {
waitStatus = exitError.Sys().(syscall.WaitStatus)
os.Exit(waitStatus.ExitStatus())
}
if err != nil {
log.Fatal(err)
}
break
}
}
}