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

时间:2018-01-26 19:32:46

标签: 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   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--提示实际上并未打印到屏幕上,因此只需检查Stdout的当前行是否包含--More--并发送\n,空格或“ q“不起作用。

Gif of <code>--More--</code> prompt disappearing.

除了解决这个问题之外,我还想过滤会话的Stdout,这样打印的唯一内容就是每个命令的输出。换句话说,我不希望将开关的提示打印到终端。

总结一下:

  1. 如何捕获和打印每个命令的输出?
  2. 如何在提示时发送新的行,空格或字母“q”?
  3. 感谢任何帮助。这是我的代码:

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

1 个答案:

答案 0 :(得分:0)

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