go-expect icon indicating copy to clipboard operation
go-expect copied to clipboard

Is there a Interact() interface ?

Open cedarwu opened this issue 4 years ago • 3 comments

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

cedarwu avatar Mar 28 '21 15:03 cedarwu

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.

hinshun avatar Mar 28 '21 20:03 hinshun

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
		}
	}
}

cedarwu avatar Mar 29 '21 07:03 cedarwu