I really liked the OneOfOne answer, which inspired me to a more generalized solution for making a variable that could match the tail of the bytes read and interrupt the lock reading (there is also no need to expand two additional threads to lock reading and writing). A known limitation (as in the original solution), if the match string appears after 64 * 1024 bytes, then this code will rotate forever.
package main import ( "fmt" "golang.org/x/crypto/ssh" "io" "log" ) var escapePrompt = []byte{'$', ' '} func main() { config := &ssh.ClientConfig{ User: "dummy", Auth: []ssh.AuthMethod{ ssh.Password("dummy"), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } client, err := ssh.Dial("tcp", "127.0.0.1:22", config) if err != nil { panic(err) } defer client.Close() session, err := client.NewSession() if err != nil { log.Fatalf("unable to create session: %s", err) } defer session.Close() modes := ssh.TerminalModes{ ssh.ECHO: 0, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } if err := session.RequestPty("xterm", 80, 40, modes); err != nil { log.Fatal(err) } w, err := session.StdinPipe() if err != nil { panic(err) } r, err := session.StdoutPipe() if err != nil { panic(err) } if err := session.Start("/bin/sh"); err != nil { log.Fatal(err) } readUntil(r, escapePrompt) //ignore the shell output write(w, "ls -lhav") out, err := readUntil(r, escapePrompt) fmt.Printf("ls output: %s\n", *out) write(w, "whoami") out, err = readUntil(r, escapePrompt) fmt.Printf("whoami: %s\n", *out) write(w, "exit") session.Wait() } func write(w io.WriteCloser, command string) error { _, err := w.Write([]byte(command + "\n")) return err } func readUntil(r io.Reader, matchingByte []byte) (*string, error) { var buf [64 * 1024]byte var t int for { n, err := r.Read(buf[t:]) if err != nil { return nil, err } t += n if isMatch(buf[:t], t, matchingByte) { stringResult := string(buf[:t]) return &stringResult, nil } } } func isMatch(bytes []byte, t int, matchingBytes []byte) bool { if t >= len(matchingBytes) { for i := 0; i < len(matchingBytes); i++ { if bytes[t - len(matchingBytes) + i] != matchingBytes[i] { return false } } return true } return false }
user892960
source share