使用Golang实现SSH会话输出的实时过滤

使用Golang实现SSH会话输出的实时过滤

大家好!
我对Go语言还比较生疏,所以这个问题可能显得有点新手。无论如何...

我需要过滤来自SSH会话的持续输出流。

使用的库是"golang.org/x/crypto/ssh"。

在尝试实现过滤SSH会话中每行新输入以匹配特定字符串的功能时,我对bytes.Buffer/io.Reader感到相当困惑。

我目前的代码似乎是传递了一个指向bytes.Buffer对象的指针:

```go
	if err := session.RequestPty("vt100", 80, 40, modes); err != nil {
		//if err := session.RequestPty("vt220", 80, 40, modes); err != nil {
		log.Printf("[ERROR] SSH PTY Error for %s (%s)", "target", err.Error())
		return
	}

	if err := session.Shell(); err != nil {
		log.Printf("[ERROR] SSH Shell Setup Error for %s (%s)", "target", err.Error())
		return
	}

	r, err := session.StdoutPipe()
	if err != nil {
		log.Printf("[ERROR] SSH Output Pipe Error for %s (%s)", "target", err.Error())
		return
	}
	var buff bytes.Buffer
	session.Stdout = &buff

在阅读相关资料后,建议的处理方法是使用类似这样的代码:

func main() {
    input := "foo\nbar\nbaz"
    scanner := bufio.NewScanner(strings.NewReader(input))
    // 实际上不需要设置,因为这是默认的分割函数
    scanner.Split(bufio.ScanLines)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}

但是,由于这个方法需要io.Reader对象,我不知道如何将我的bytes.Buffer与之连接。再次说明,我是个初学者,可能还没掌握Go语言的基础知识。

我应该如何继续?如果不是使用上述代码,我也很乐意改变方法。我知道SSH库中有StdOutPipe可用,但我不确定这是否有帮助。

来自SSH会话的输出本质上是网络设备上的调试命令。

非常感谢!


更多关于使用Golang实现SSH会话输出的实时过滤的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

嗨,我不太明白你想做什么;听起来你是在尝试过滤掉不匹配预期子字符串的行。如果是这种情况,你不能直接用 grep 过滤数据吗?

// 代码示例保留原样
func main() {
    fmt.Println("hello world")
}

更多关于使用Golang实现SSH会话输出的实时过滤的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


引用 mnantel:

然而,由于此方法需要 io.Reader 对象,我不知道如何将我的 bytes.Buffer 与此关联。我确实是个初学者,可能还没掌握 Go 的基础知识。

你好。bytes.Buffer 实现了 reader 接口(参见 bytes 包 - bytes - Go 语言包),因此你可以直接使用它。

你可以使用 StdoutPipe 来获取 SSH 会话的实时输出流,然后通过 bufio.Scanner 逐行处理并过滤。以下是一个完整的示例:

package main

import (
    "bufio"
    "log"
    "strings"

    "golang.org/x/crypto/ssh"
)

func main() {
    // SSH 连接配置和建立(示例)
    config := &ssh.ClientConfig{
        User: "username",
        Auth: []ssh.AuthMethod{
            ssh.Password("password"),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", "host:22", config)
    if err != nil {
        log.Fatal("Failed to dial: ", err)
    }
    defer client.Close()

    session, err := client.NewSession()
    if err != nil {
        log.Fatal("Failed to create session: ", err)
    }
    defer session.Close()

    modes := ssh.TerminalModes{
        ssh.ECHO:          0,
        ssh.TTY_OP_ISPEED: 14400,
        ssh.TTY_OP_OSPEED: 14400,
    }

    if err := session.RequestPty("vt100", 80, 40, modes); err != nil {
        log.Fatal("Request for pseudo terminal failed: ", err)
    }

    // 获取标准输出管道
    stdout, err := session.StdoutPipe()
    if err != nil {
        log.Fatal("Unable to setup stdout: ", err)
    }

    if err := session.Shell(); err != nil {
        log.Fatal("Failed to start shell: ", err)
    }

    // 使用 bufio.Scanner 实时读取输出
    scanner := bufio.NewScanner(stdout)
    for scanner.Scan() {
        line := scanner.Text()
        // 过滤包含特定字符串的行
        if strings.Contains(line, "特定字符串") {
            log.Printf("过滤后的输出: %s", line)
        }
    }

    if err := scanner.Err(); err != nil {
        log.Printf("读取输出时出错: %v", err)
    }

    session.Wait()
}

关键点:

  • 使用 session.StdoutPipe() 获取 io.Reader 接口
  • bufio.NewScanner 可以直接使用这个 Reader
  • scanner.Scan() 循环中实时处理每一行输出
  • 在循环内添加你的过滤逻辑

对于你的原始代码,主要问题是直接将 bytes.Buffer 设置为 session.Stdout,这会缓冲所有输出而不是实时处理。使用 StdoutPipe 配合 Scanner 是更合适的实时处理方式。

如果需要同时处理标准错误输出,可以类似地使用 session.StderrPipe()

回到顶部