Git Product home page Git Product logo

goexpect's People

Contributors

cshung avatar ctkeyser avatar dankenigsberg avatar jason-cooke avatar joshbarry92 avatar julienvdg avatar marco-m avatar marek5050 avatar qq827435393 avatar rjoleary avatar ryandgoulding avatar skalle avatar stmuk avatar tinti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goexpect's Issues

Nuking the buffer after a match is not correct IMHO

In ExpectSwitchCase() we do:

			// Clear the buffer directly after match.
			o := tbuf.String()
                        tbuf.Reset()

This means that back to back Expect will not work if the matching string for the second Expect call is already in buffer.

For example the following code will fail:

exp.Expect(regexp.MustComplie("StringA"))
exp.Expect(regexp.MustCopmile("StrinbB"))

If our buffer is already "StringA...StringB" by the time we call exp.Expect(regexp.MustComplie("StringA")).

Real world use case is doing multiple Expect to much long strings during bootup, will work when run against real situation, but will fail during UT.

Instead of nuking the whole buffer, we should only be deleting up to the point of the last match. That's how the rest of "expect" libraries work if I am not mistaken.

scp lager file timeout

It happened that there is no data in e when timer.C was up, in funtion ExpectSwitchCase.

Go 1.13: Spawn fails with "operation not permitted"

Spawn fails on Go 1.13:

$ go run ./examples/process/ 10
F0625 11:06:45.549888  104755 process.go:45] fork/exec /usr/bin/bc: operation not permitted
exit status 1

Culprit is https://go-review.googlesource.com/c/go/+/178919 ("syscall: use Ctty before fd shuffle").

If I'm following correctly, the problem is here:

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setsid:  true,
		Setctty: true}

Setting Setctty sets the controlling terminal to SysProcAttr.Ctty, which is unset (i.e., 0), which is probably not the desired behavior.

goterm is too old

D:\01work\internal_software\trunk\devLicense\wlic\client>go version
go version go1.17 windows/amd64

D:\01work\internal_software\trunk\devLicense\wlic\client>go build

github.com/google/goterm/term

C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:202:32: not enough arguments in call to syscall.Syscall
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:202:33: undefined: syscall.SYS_IOCTL
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:213:32: not enough arguments in call to syscall.Syscall
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:213:33: undefined: syscall.SYS_IOCTL
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:288:32: not enough arguments in call to syscall.Syscall
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:288:33: undefined: syscall.SYS_IOCTL
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:310:32: not enough arguments in call to syscall.Syscall
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:310:33: undefined: syscall.SYS_IOCTL
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:319:32: not enough arguments in call to syscall.Syscall
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:319:33: undefined: syscall.SYS_IOCTL
C:\Users\yxhlc\go\pkg\mod\github.com\google\[email protected]\term\termios.go:319:32: too many errors

D:\01work\internal_software\trunk\devLicense\wlic\client>

Allow ".Run(...)" for a specific command on SSH sessions or expose the session object

Right now when using SpawnSSH/SpawnSSHPTY goexpect will create a SSH Session object and call the Shell method automatically. While this works great for lots of network devices, for other devices (ex: servers) it would be great to be able to call the Run method without creating a shell as that adds additional parsing complexity ($PS1, etc) when you only want to run a single command. I think exporting the underlying Session object could work or adding the command to run as an Option which would change logic in SpawnSSHPTY to call session.Run instead of session.Shell would also work.

Having two SpawnGeneric, each with different verbosity configuration

Hi
We are using goexpect at https://github.com/kubevirt/kubevirt [1]
With the following settings to SpawnGeneric:

opts = append(opts, expect.Verbose(true))
opts = append(opts, expect.VerboseWriter(GinkgoWriter))

[1] https://github.com/kubevirt/kubevirt/blob/75674879e91dfc24a340cae54c92ea7509e42cb4/tests/console/console.go#L209

On one hand it is perfect for us that only upon error or verbose mode, we see all the logged info.
The problem is that if there is an error, we have a custom error reporter, which also uses SpawnGeneric
in order to trigger some more commands that collect data.
Those commands would print as well all the collected info to the console, which cause it to be too loaded with info
which is not needed (it is saved to files as well where it belongs).

Is there a way to have two SpawnGeneric, where one prints to GinkgoWriter, while the other prints to /dev/null
or doesn't print at all ?

Tried few configurations, but no luck yet (changes might be required in the NewExpecter as well i believe)
For example tried to have a different buffer and control it (I believe I didn't do it right if it suppose to work)

Thanks

Send command do not respect timeout variable

Sometimes, when we have network connectivity issues inside of cluster our tests is stuck on

goroutine 20 [chan send, 170 minutes]:
kubevirt.io/kubevirt/vendor/github.com/google/goexpect.(*GExpect).Send(0xc000f96500, 0x15464fb, 0x1, 0xc000d40e68, 0x40d72f)
        /root/go/src/kubevirt.io/kubevirt/vendor/github.com/google/goexpect/expect.go:1093 +0x90
kubevirt.io/kubevirt/vendor/github.com/google/goexpect.(*GExpect).ExpectBatch(0xc000f96500, 0xc000cf0360, 0x9, 0x9, 0x29e8d60800, 0xc000d1d900, 0x3e, 0x0, 0x1711660, 0xc000cb65d0)
        /root/go/src/kubevirt.io/kubevirt/vendor/github.com/google/goexpect/expect.go:595 +0x7b9
kubevirt.io/kubevirt/tests.LoggedInCirrosExpecter(0xc0010b1800, 0xc000c8aa40, 0xc000704f00, 0x0, 0x0)
        /root/go/src/kubevirt.io/kubevirt/tests/utils.go:2069 +0x534
kubevirt.io/kubevirt/tests_test.generateHelloWorldServer(0xc0010b1800, 0x1756360, 0xc000704f00, 0x50, 0x1546d7f, 0x3)
...

our LoggedInCirrosExpecter uses ExpectBatch method with 3 minutes timeout, but it stuck forever if it no input from the expecter.

Remove glog package dependency to avoid 'flag redefined'

The package http://github.com/golang/glog defines several flags in its init().

When a program defines some flags and imports http://github.com/google/goexpect it may have some flags redefined.

Would be great if goexpect (due to glog) does not restrict the set of flags that can be used. For this I have two proposals:

  • Drop glog completely and use log package.
  • Drop glog partially by allowing the user to set their custom logger for the package. Implement glog and log interface in this custom logger.

The first one is poorly implemented here: http://github.com/tinti/goexpect

Send file over SSH

Wondering if there's any way to send a file over SSH.
I'm working with automation of configuration using NETCONF, and need to send over a file with the configuration and subsequently respond to prompts.

More specifically, I need to run the following SSH command:
ssh -o StrictHostKeyChecking=no -p $PORT admin@$HOST -s netconf < $CONFIG_FILE

The python pexpect package allows the spawning of a command to be executed. So I could perform the following:

cmd_to_execute = f'/bin/bash -c "ssh -o StrictHostKeyChecking=no -p {cm_port} admin@{cm_host} -s netconf < {config_file}"'
child = pexpect.spawn(cmd_to_execute)

What would be an equivalent goexpect way of performing such action?

`Expect` wouldn't work when GenericSpawn a `ssh user@address` command

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

Allow Spawning Command Line Args with Embedded Spaces

For example, the command line touch 'x y' contains two args, not three: touch and x y. goexpect does not support arguments containing spaces when spawning processes.

The proposal is to change the signature of Spawn from:

func Spawn(command string, timeout time.Duration, opts ...Option) (*GExpect, <-chan error, error)

To:

func Spawn(command []string, timeout time.Duration, opts ...Option) (*GExpect, <-chan error, error)

Setctty set but Ctty not valid in child

Yesterday I had working code based on the AsyncInteractChannels example.

Today with the same code I am getting the error Setctty set but Ctty not valid in child

It appears I am triggering the issue described here golang/go#29458 but I'm not sure what to check further to confirm.

I've upgraded golang from 1.15.2 to 1.15.5 and still get the error.

Running on MacOS.

Redirect non-verbose logging

Hello, thanks for this cool package!
I am using the VerboseWriter option to redirect verbose logging to my implementation of io.Writer. However, it looks like there's no way to redirect goexpect's non-verbose logging in the same way, or am I missing something? I would like to be able to redirect both since I'm using custom logging code, currently the non-verbose logging falls out of line.

Problems in README.md

In example code ssh_example,

	e.ExpectBatch([]expect.Batcher{
		&expect.BCas{[]expect.Caser{
			&expect.Case{R: regexp.MustCompile(`router#`), T: expect.OK()},
			&expect.Case{R: regexp.MustCompile(`Login: `), S: *user,
				T: expect.Continue(expect.NewStatus(codes.PermissionDenied, "wrong username")), Rt: 3},
			&expect.Case{R: regexp.MustCompile(`Password: `), S: *pass1, T: expect.Next(), Rt: 1},
----> here              &expect.Case{R: regexp.MustCompile(`Password: `), S: *pass1,
				T: expect.Continue(expect.NewStatus(codes.PermissionDenied, "wrong password")), Rt: 1},
		}},
	}, timeout)

I believe it means to try pass2 instead of trying pass1 again.

Spawn() fails with "inappropriate ioctl for device" error on Go 1.11

  • macOS: 10.13.6
  • Go: 1.11

Tests on master branch fails:

goexpect/master$ go test .
2018/09/11 23:43:37 at login prompt
2018/09/11 23:43:37 at password prompt
2018/09/11 23:43:39 Done sent
E0911 23:43:39.901595   19055 expect_test.go:136] Accept failed: accept tcp [::]:65226: use of closed network connection
E0911 23:43:39.910121   19055 expect_test.go:204] PTY cols/rows: 240/22 want: 120/40
E0911 23:43:39.910250   19055 expect_test.go:136] Accept failed: accept tcp [::]:65231: use of closed network connection
2018/09/11 23:43:39 Write failed: io: read/write on closed pipe
2018/09/11 23:43:39 Write failed: io: read/write on closed pipe
--- FAIL: TestSpawn (0.00s)
    expect_test.go:948: Nil return code: Spawn("/bin/true") = true want: false, err: inappropriate ioctl for device
    expect_test.go:948: Non nil return code: Spawn("/bin/false") = true want: false, err: inappropriate ioctl for device
    expect_test.go:948: Spawn cat: Spawn("/bin/cat") = true want: false, err: inappropriate ioctl for device
--- FAIL: TestSpawnWithArgs (0.00s)
    expect_test.go:971: Spawn(echo 'a   b') failed: inappropriate ioctl for device
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x58 pc=0x11ee48c]

goroutine 46 [running]:
testing.tRunner.func1(0xc000110900)
	/usr/local/opt/go/libexec/src/testing/testing.go:792 +0x387
panic(0x123f720, 0x144d5a0)
	/usr/local/opt/go/libexec/src/runtime/panic.go:513 +0x1b9
github.com/google/goexpect.(*GExpect).ExpectSwitchCase(0x0, 0xc000251ec8, 0x1, 0x1, 0x17d78400, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
	/Users/hachi8833/deve/golang/gopath/sys/src/github.com/google/goexpect/expect.go:620 +0x1cc
github.com/google/goexpect.(*GExpect).Expect(0x0, 0xc0004020a0, 0x17d78400, 0xc000251f58, 0x1, 0x1, 0x0, 0x0, 0x0, 0x12c4100)
	/Users/hachi8833/deve/golang/gopath/sys/src/github.com/google/goexpect/expect.go:1125 +0xd1
github.com/google/goexpect.TestSpawnWithArgs(0xc000110900)
	/Users/hachi8833/deve/golang/gopath/sys/src/github.com/google/goexpect/expect_test.go:975 +0x139
testing.tRunner(0xc000110900, 0x1295258)
	/usr/local/opt/go/libexec/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/usr/local/opt/go/libexec/src/testing/testing.go:878 +0x353
FAIL	github.com/google/goexpect	4.220s

Receive bufferSize should be configurable

goexpect fails when the client expects payloads larger than the default buffer size.

A dynamically growing byte slice will not work in this instance, due to the fact that the PTY File is not closed after receiving command output (i.e., does not receive io.EOF). As such, something like ioutil.ReadAll(...) cannot be used in this context, and will eventually just timeout waiting for io.EOF or an error.

Support should be added to at least make bufferSize configurable, preferably per GExpect instance.

Readme assumes too much knowledge

The readme isn't useful unless you already know what expect is. If you don't, then it is meaningless (and it's hard to google "expect").

How to send 'Ctrl-C' to the interactive shell spawned by SpawnWithArgs

Say, I run cat /proc/kmsg as a root user on the interfactive SSH shell spawned by SpawnWithArgs, but it will hangs for ever (since you wouldn't cat anything from the magic file /proc/kmsg even as root), so no following commands sent to this SSH shell will not be executed by the SSH shell since it is haning on. I'd like invoke Ctrl-C in this SSH shell spawned by goexpect to stop cat progress clearing the shell, just like what we will do in an actual one.

I've tried

  1. sending ASCII code \003 (by calling exp.Write()) wouldn't work.
  2. SendSignal batcher seems send signals to the SSH progress itself, not she SHELL inside the SSH session.

Are there any ways to do this? What did I miss here?

when using goroutines, the connection is timed out

I am having a problem when using goroutines. If i make connections one by one - the connections are successful, I get the data.
But if I run many goroutines at the same time, then they freeze and die by timeout. And I tracked down - freezes occur after sending the password. What am I doing wrong?

import (
	"fmt"
	"log"
	"regexp"
	"sync"
	"time"
	expect "github.com/google/goexpect"
)
const (
	timeout = 30 * time.Second
)
var (
	userRE   = regexp.MustCompile("UserName:")
	passRE   = regexp.MustCompile("PassWord:")
	promptRE = regexp.MustCompile("admin#")

	list []string = []string{"dlink1.domain.com",
                                         "dlink2.domain.com",
                                         "dlink3.domain.com",
                                         "dlink4.domain.com"
                                         }
)

func main() {
	log.Println("Telnet example start")

	// Running multiple goroutines
	var wg sync.WaitGroup
	wg.Add(len(list))

	for _, router := range list {
        // the problem occurs here
	/* go */	CallToRouter("username", "pass", router, "1a:1a:1a:1a:1a:1a", searcher, &wg)
	}
	wg.Wait()
	log.Println("Done!")

}

func CallToRouter(user, pass, router, macForSearch string, regexp *regexp.Regexp, wg *sync.WaitGroup) {
	defer wg.Done()

	// Connect to router
	e, _, err := expect.Spawn(fmt.Sprintf("telnet %s", router), -1)
	if err != nil {
		log.Panic(err)
		return
	}
       defer e.Close()

	// Authorizer, exec command, exit
	_, _, err = e.Expect(userRE, timeout)
	if err != nil {
		log.Panic(err)
		return
	}
	err = e.Send(user + "\n")
	if err != nil {
		log.Panic(err)
		return
	}
	_, _, err = e.Expect(passRE, timeout)
	if err != nil {
		log.Panic(err)
		return
	}
	err = e.Send(pass + "\n")
	if err != nil {
		log.Panic(err)
		return
	}
	_, _, err := e.Expect(promptRE, timeout)
	if err != nil {
		log.Panic(err)
		return
	}

	err = e.Send("sh fdb mac " + macForSearch + "\n")
	if err != nil {
		log.Panic(err)
		return
	}
	result, _, _ := e.Expect(promptRE, timeout)
	if err != nil {
		log.Panic(err)
		return
	}
	err = e.Send("logout\n")
	if err != nil {
		log.Panic(err)
		return
	}

	log.Printf("%s:\n%s", router, result)
}

Unable to get output from Cisco devices via ssh

I've had a good experience using this package to ssh into servers. However, I have not been able to get it to work on a Cisco device via ssh yet. The native go ssh package works, but not this one. Since I need to do a few complex tasks, I'd rather use this package if possible.

The first time that I execute e.Expect(promptRE, timeout), it shows the login banner. However, when I send another command and call e.Expect again, the output received is the command I sent. I tried the exact verbose setup from the verbose example and this was the output...

Match for RE: "Password:" found: ["Password:"] Buffer: Cisco UCS Fabric Interconnect
Password:
Sent: "password\n"
Match for RE: "#" found: ["#"] Buffer:
Cisco Nexus Operating System (NX-OS) Software
TAC support: http://www.cisco.com/tac
Copyright (c) 2009, Cisco Systems, Inc. All rights reserved.
The copyrights to certain works contained in this software are
owned by other third parties and used and distributed under
license. Certain components of this software are licensed under
the GNU General Public License (GPL) version 2.0 or the GNU
Lesser General Public License (LGPL) Version 2.1. A copy of each
such license is available at
http://www.opensource.org/licenses/gpl-2.0.php and
http://www.opensource.org/licenses/lgpl-2.1.php
DEV-1-A#
Sent: "show version\n"
Match for RE: "DEV-1-A#" found: ["DEV-1-A#"] Buffer: show version
DEV-1-A#
cmd: show version: result: show version

The code producing this was...

e.Send("show version\n")
time.Sleep(time.Second)
result, _, _ = e.Expect(promptRE, timeout)
fmt.Println("cmd: %s: result: %s\n", cmd, result)

Please let me know if you have any thoughts on how to fix this. I have already tried playing around with the terminal width and had no luck.

Support for windows/amd64 ?

C:\Users\u1\go>go version
go version go1.10.3 windows/amd64

C:\Users\u1\go>go get -v github.com/google/goexpect
github.com/google/goterm/term
# github.com/google/goterm/term
src\github.com\google\goterm\term\termios.go:202:32: not enough arguments in call to syscall.Syscall
src\github.com\google\goterm\term\termios.go:202:33: undefined: syscall.SYS_IOCTL
src\github.com\google\goterm\term\termios.go:213:32: not enough arguments in call to syscall.Syscall
src\github.com\google\goterm\term\termios.go:213:33: undefined: syscall.SYS_IOCTL
src\github.com\google\goterm\term\termios.go:288:32: not enough arguments in call to syscall.Syscall
src\github.com\google\goterm\term\termios.go:288:33: undefined: syscall.SYS_IOCTL
src\github.com\google\goterm\term\termios.go:310:32: not enough arguments in call to syscall.Syscall
src\github.com\google\goterm\term\termios.go:310:33: undefined: syscall.SYS_IOCTL
src\github.com\google\goterm\term\termios.go:319:32: not enough arguments in call to syscall.Syscall
src\github.com\google\goterm\term\termios.go:319:33: undefined: syscall.SYS_IOCTL
src\github.com\google\goterm\term\termios.go:319:32: too many errors

Is there a Interact() interface

Hi,

How to gives control of the child process to the interactive user (the human at the keyboard) like the interact() method in pexpect?

Useless break statement

goexpect/expect.go

Lines 1262 to 1264 in c416f18

if _, err := e.pty.Master.Write([]byte(sstr)); err != nil || !e.check() {
log.Printf("send failed: %v", err)
break

The switch case block does not require break. If break for loop, you need a label.

Multiple lines of output are causing timeouts

I am attempting to write expect around some queries of Tivoli Storage Manager (IBM Spectrum Protect) and have found that if my queries return only a few lines of output everything works but if my queries return many lines of output I hit the expect timeout.

I modified my program to do a simpler SSH command where executing hostname is successful but an operation that lists the contents of a directory with a few lines of output times out.

package main

import (
	"log"
	"os"
	"regexp"
	"time"

	expect "github.com/google/goexpect"
)

var (
	passRE   = regexp.MustCompile("password:")
	promptRE = regexp.MustCompile(`\[tdockendorf@repo ~\]`)
)

func main() {
	cmd := "ssh repo"
	timeout := time.Duration(5) * time.Second
	e, _, err := expect.Spawn(cmd, timeout, expect.Verbose(true), expect.VerboseWriter(os.Stdout))
	if err != nil {
		log.Fatal(err)
	}
	defer e.Close()

	content, matches, err := e.Expect(passRE, timeout)
	if err != nil {
		log.Fatalf("error getting password prompt: %v", err)
	}
	log.Printf("content1: %s matches1: %v", content, matches)
	err = e.Send(os.Getenv("PASSWORD") + "\n")
	if err != nil {
		log.Fatalf("error sending password: %v", err)
	}
	content, matches, err = e.Expect(promptRE, timeout)
	if err != nil {
		log.Fatalf("error getting prompt: %v", err)
	}
	log.Printf("content2: %s matches2: %v", content, matches)
	err = e.Send("hostname\n")
	if err != nil {
		log.Fatalf("error sending command1: %v", err)
	}
	content, matches, err = e.Expect(promptRE, timeout)
	if err != nil {
		log.Fatalf("error getting prompt: %v", err)
	}
	log.Printf("content3: %s matches3: %v", content, matches)
	err = e.Send("ls -la /var/www/repos/public/ondemand/\n")
	if err != nil {
		log.Fatalf("error sending command2: %v", err)
	}
	content, matches, err = e.Expect(regexp.MustCompile("Protect:"), timeout)
	if err != nil {
		log.Fatalf("error getting prompt2: %v", err)
	}
	log.Printf("content4: %s matches4: %v", content, matches)
	e.Send("exit\n")
}

OUTPUT:

$ ./test
Match for RE: "password:" found: ["password:"] Buffer: tdockendorf@repo's password: 
2020/11/11 10:26:14 content1: tdockendorf@repo's password:  matches1: [password:]
Sent: "OMIT-PASSWORD\n"
Match for RE: "\\[tdockendorf@repo ~\\]" found: ["[tdockendorf@repo ~]"] Buffer: 
Last login: Wed Nov 11 10:24:09 2020 from pitzer-rw01.ten.osc.edu
******************************************************************************

   This system is for the use of authorized users only.  Individuals using
   this computer system without authority, or in excess of their authority,
   are subject to having all of their activities on this system monitored
   and recorded by system personnel.  In the course of monitoring individuals
   improperly using this system, or in the course of system maintenance,
   the activities of authorized users may also be monitored.  Anyone using
   this system expressly consents to such monitoring and is advised that if
   such monitoring reveals possible evidence of criminal activity, system
   personnel may provide the evidence of such monitoring to law enforcement
   officials.

******************************************************************************
[tdockendorf@repo ~]$ 
2020/11/11 10:26:14 content2: 
Last login: Wed Nov 11 10:24:09 2020 from pitzer-rw01.ten.osc.edu
******************************************************************************

   This system is for the use of authorized users only.  Individuals using
   this computer system without authority, or in excess of their authority,
   are subject to having all of their activities on this system monitored
   and recorded by system personnel.  In the course of monitoring individuals
   improperly using this system, or in the course of system maintenance,
   the activities of authorized users may also be monitored.  Anyone using
   this system expressly consents to such monitoring and is advised that if
   such monitoring reveals possible evidence of criminal activity, system
   personnel may provide the evidence of such monitoring to law enforcement
   officials.

******************************************************************************
[tdockendorf@repo ~]$  matches2: [[tdockendorf@repo ~]]
Sent: "hostname\n"
Match for RE: "\\[tdockendorf@repo ~\\]" found: ["[tdockendorf@repo ~]"] Buffer: repo.OMIT
[tdockendorf@repo ~]$ 
2020/11/11 10:26:14 content3: repo.OMIT
[tdockendorf@repo ~]$  matches3: [[tdockendorf@repo ~]]
Sent: "ls -la /var/www/repos/public/ondemand/\n"
2020/11/11 10:26:19 error getting prompt2: expect: timer expired after 5 seconds

Commands executed outside the program:

$ ssh repo
tdockendorf@repo's password: 
Last login: Wed Nov 11 10:26:14 2020 from pitzer-rw01.ten.osc.edu
******************************************************************************

   This system is for the use of authorized users only.  Individuals using
   this computer system without authority, or in excess of their authority,
   are subject to having all of their activities on this system monitored
   and recorded by system personnel.  In the course of monitoring individuals
   improperly using this system, or in the course of system maintenance,
   the activities of authorized users may also be monitored.  Anyone using
   this system expressly consents to such monitoring and is advised that if
   such monitoring reveals possible evidence of criminal activity, system
   personnel may provide the evidence of such monitoring to law enforcement
   officials.

******************************************************************************
[tdockendorf@repo ~]$ hostname
repo.hpc.osc.edu
[tdockendorf@repo ~]$ time ls -la /var/www/repos/public/ondemand/
total 80
drwxrwxr-x 13 tdockendorf oodpkg  4096 Aug 19 09:04 .
drwxrwxr-x 23 tdockendorf    103  8192 Apr  5  2019 ..
drwxr-xr-x  4 oodpkg      oodpkg  4096 May  2  2018 1.3
drwxr-xr-x  4 oodpkg      oodpkg  4096 Jan  7  2019 1.4
drwxr-xr-x  4 oodpkg      oodpkg  4096 Feb  4  2019 1.5
drwxr-xr-x  4 oodpkg      oodpkg  4096 Sep 30  2019 1.6
drwxr-xr-x  4 oodpkg      oodpkg  4096 Aug 19 13:32 1.7
drwxr-xr-x  4 oodpkg      oodpkg  4096 Aug 19 09:04 1.8
drwxrwxr-x  2 oodpkg      oodpkg 16384 Apr  8  2020 archive
drwxrwxr-x  6 oodpkg      oodpkg  4096 Nov  6 11:28 build
drwxr-xr-x  4 oodpkg      oodpkg  4096 Jul  3  2019 ci
drwxr-xr-x  2 oodpkg      oodpkg  4096 Nov  5 14:11 images
drwxr-xr-x  4 oodpkg      oodpkg 12288 Aug 19 13:34 latest
-rw-r--r--  1 root        root    1739 Feb 13  2018 RPM-GPG-KEY-ondemand

real    0m0.008s
user    0m0.000s
sys     0m0.004s

Possible memory leak because of Ticker.

chTicker := time.NewTicker(check)

Hello,
After running expect a couple of thousand times it seems there's a memory leak that occurs. I think I've traced it down to the referenced lines and reading through the NewTicker comments they recommend:

// The duration d must be greater than zero; if not, NewTicker will panic.
// Stop the ticker to release associated resources.

I couldn't find the code to stop the Ticker within expect.go. Is there a reason there's no Stop()?

defer chTicker.Stop()

Heap pprof profile without Stop

68.93MB of 68.93MB total (  100%)
Dropped 52 nodes (cum <= 0.34MB)
      flat  flat%   sum%        cum   cum%
      46MB 66.74% 66.74%       46MB 66.74%  runtime.makechan
   11.50MB 16.68% 83.42%    45.85MB 66.51%  time.NewTicker
       4MB  5.80% 89.22%    18.50MB 26.84%  time.NewTimer
    2.85MB  4.13% 93.35%     2.85MB  4.13%  runtime.addtimerLocked
    0.88MB  1.28% 94.63%     0.88MB  1.28%  compress/flate.NewWriter
    0.64MB  0.92% 95.55%     0.64MB  0.92%  github.com/golang/glog.(*syncBuffer).rotateFile

Heap pprof profile with Stop

18236.91kB of 18236.91kB total (  100%)
Dropped 64 nodes (cum <= 91.18kB)
      flat  flat%   sum%        cum   cum%
 9728.73kB 53.35% 53.35%  9728.73kB 53.35%  runtime.makechan
 5632.34kB 30.88% 84.23% 15361.08kB 84.23%  time.NewTimer
 1121.44kB  6.15% 90.38%  1121.44kB  6.15%  runtime.addtimerLocked
  650.62kB  3.57% 93.95%   650.62kB  3.57%  github.com/golang/glog.(*syncBuffer).rotateFile
  591.75kB  3.24% 97.19%   591.75kB  3.24%  crypto/elliptic.initTable
  512.02kB  2.81%   100%   512.02kB  2.81%  vendor/golang_org/x/net/http2/hpack.addDecoderNode

Example code:
https://github.com/marek5050/GoPprof/blob/master/src/github.com/marek5050/GoProfiling/cmd/lser/main.go

Option to Tee output to a file

For example, I would like to see the raw output of the process in a log file. The word "Tee" comes from the GNU tee command.

How to check if the match succeeded?

Hi,

I'm fairly new to go and I'm having a hard time following the source. How can I determine if the regex match of the "Expect" function succeeded?

Thanks,
-G

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.