Session Golang-过滤活动SSH会话的标准输出

Session Golang-过滤活动SSH会话的标准输出,session,go,networking,ssh,network-programming,Session,Go,Networking,Ssh,Network Programming,我正在用Go编写一个SSH客户机,它连接到一个交换机并运行一系列配置命令。到目前为止,我能够成功地连接到交换机,运行所需的命令,并打印会话的输出。当命令输出过长时,开关希望输入\n、空格或“q”时,就会出现问题。例如: switch#show int status Port Name Status Vlan Duplex Speed Type Gi1/0/1 notconnect 10

我正在用Go编写一个SSH客户机,它连接到一个交换机并运行一系列配置命令。到目前为止,我能够成功地连接到交换机,运行所需的命令,并打印会话的输出。当命令输出过长时,开关希望输入
\n
、空格或“q”时,就会出现问题。例如:

switch#show int status

Port      Name               Status       Vlan       Duplex  Speed Type
Gi1/0/1                      notconnect   100          auto   auto 10/100/1000BaseTX
Gi1/0/2                      connected    915        a-full  a-100 10/100/1000BaseTX
Gi1/0/3                      notconnect   100          auto   auto 10/100/1000BaseTX
Gi1/0/4                      notconnect   100          auto   auto 10/100/1000BaseTX
Gi1/0/5                      notconnect   230          auto   auto 10/100/1000BaseTX
...
Po1       sw-sww-100-sww-0-0 connected    trunk      a-full    10G
 --More-- # Program hangs here; expecting a new line, space, or 'q'
--More--
提示实际上并没有打印到屏幕上,因此只需检查
标准输出的当前行是否包含
--More--
并发送
\n
空格或“q”就行了

除了解决这个问题之外,我还想过滤会话的
Stdout
,以便只打印每个命令的输出。换句话说,我不希望开关的提示被打印到终端上

总而言之:

  • 如何仅捕获和打印每个命令的输出
  • 提示时如何发送新行、空格或字母“q”
  • 感谢您的帮助。这是我的密码:

    package main
    
    import (
        "bufio"
        "fmt"
        "golang.org/x/crypto/ssh"
        "io"
        "log"
        "os"
        "time"
    )
    
    type Device struct {
        Config  *ssh.ClientConfig
        Client  *ssh.Client
        Session *ssh.Session
        Stdin   io.WriteCloser
        Stdout  io.Reader
        Stderr  io.Reader
    }
    
    func (d *Device) Connect() error {
        client, err := ssh.Dial("tcp", os.Args[1]+":22", d.Config)
        if err != nil {
            return err
        }
        session, err := client.NewSession()
        if err != nil {
            return err
        }
        sshIn, err := session.StdinPipe()
        if err != nil {
            return err
        }
        sshOut, err := session.StdoutPipe()
        if err != nil {
            return err
        }
        sshErr, err := session.StderrPipe()
        if err != nil {
            return err
        }
        d.Client = client
        d.Session = session
        d.Stdin = sshIn
        d.Stdout = sshOut
        d.Stderr = sshErr
        return nil
    }
    
    func (d *Device) SendCommand(cmd string) error {
        if _, err := io.WriteString(d.Stdin, cmd+"\r\n"); err != nil {
            return err
        }
        return nil
    }
    
    func (d *Device) SendConfigSet(cmds []string) error {
        for _, cmd := range cmds {
            if _, err := io.WriteString(d.Stdin, cmd+"\r\n"); err != nil {
                return err
            }
            time.Sleep(time.Second)
        }
        return nil
    }
    
    func (d *Device) PrintOutput() {
        r := bufio.NewReader(d.Stdout)
        for {
            text, err := r.ReadString('\n')
            fmt.Printf("%s", text)
            if err == io.EOF {
                break
            }
        }
    }
    
    func (d *Device) PrintErr() {
        r := bufio.NewReader(d.Stderr)
        for {
            text, err := r.ReadString('\n')
            fmt.Printf("%s", text)
            if err == io.EOF {
                break
            }
        }
    }
    
    func main() {
        sshConf := ssh.Config{}
        sshConf.Ciphers = append(sshConf.Ciphers, "aes128-cbc", "3des-cbc", "blowfish-cbc", "arcfour")
        config := &ssh.ClientConfig{
            Config: sshConf,
            User:   "mwalto7",
            Auth: []ssh.AuthMethod{
                ssh.Password("Lion$Tiger$Bear$"),
            },
            HostKeyCallback: ssh.InsecureIgnoreHostKey(),
            Timeout:         time.Second * 5,
        }
    
        sw := &Device{Config: config}
    
        fmt.Println("Connecting to ", os.Args[1])
        if err := sw.Connect(); err != nil {
            log.Fatal(err)
        }
        defer sw.Client.Close()
        defer sw.Session.Close()
        defer sw.Stdin.Close()
    
        if err := sw.Session.Shell(); err != nil {
            log.Fatal(err)
        }
    
        commands := []string{"show int status", "exit"}
        if err := sw.SendConfigSet(commands); err != nil {
            log.Fatal(err)
        }
    
        sw.Session.Wait()
    
        sw.PrintOutput()
        sw.PrintErr()
    }
    

    我修复了这个问题,在连接到交换机之后,在发送其余命令之前,发送命令
    终端长度0
    。这通过将开关的终端高度设置为0禁用了
    -More-
    提示,允许显示命令的整个输出

    什么意思?
    --更多--未打印。用户如何知道输入内容?另一方面,该设备是否没有编写命令脚本的方法,或者至少关闭交互式输入?@JimB在
    标准输出中找不到
    --More--
    提示,并且没有打印到屏幕上。按enter键或空格键足够多次以查看命令的整个输出后,提示就消失了。@JimB我添加了提示的gif。程序可能通过命令
    more
    来引导其输出。当你没有在控制台上运行程序时,它真的在等待输入吗?你应该能够在方法中破解TTY设置以关闭ECHO(#1)并请求更大的终端大小,以防止需要输入
    q
    (#2)。也就是说,SNMP可能更适合您需要做的事情,请再看一看。