SSH:是否可以通过伪终端从会话中获取STDERR?

时间:2016-08-24 08:54:10

标签: go ssh pty

这个问题是关于golang.org/x/crypto/ssh包,也许是伪终端行为。

代码

这是演示代码。您可以在本地计算机上运行它,只需更改凭据即可访问SSH。

package main

import (
    "bufio"
    "fmt"
    "golang.org/x/crypto/ssh"
    "io"
)

func main() {
    var pipe io.Reader
    whichPipe := "error" // error or out

    address := "192.168.1.62:22"
    username := "username"
    password := "password"

    sshConfig := &ssh.ClientConfig{
        User: username,
        Auth: []ssh.AuthMethod{ssh.Password(password)},
    }

    connection, err := ssh.Dial("tcp", address, sshConfig)
    if err != nil {
        panic(err)
    }

    session, err := connection.NewSession()
    if err != nil {
        panic(err)
    }

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

    if err := session.RequestPty("xterm", 80, 0, modes); err != nil {
        session.Close()
        panic(err)
    }

    switch whichPipe {
    case "error":
        pipe, _ = session.StderrPipe()
    case "out":
        pipe, _ = session.StdoutPipe()
    }

    err = session.Run("whoami23")

    scanner := bufio.NewScanner(pipe)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
}

实际结果

空行

预期结果

bash: whoami23: command not found

当前“解决方案”

要获得预期结果,您有两种选择:

  1. whichPipe值更改为out。是的,如果您使用tty,所有错误都会转到stdout。
  2. 删除session.RequestPty。但在我的情况下,我需要运行sudo命令,这些命令需要tty(服务器不在我的控制范围内,因此我无法禁用此要求)。
  3. 我用第三种方式。我从err检查err = session.Run("whoami23"),如果不是nil,我将session.StdoutPipe()的内容标记为STDERR。

    但这种方法有限制。例如,如果我运行类似sudo sh -c 'uname -r; whoami23;'的内容,则整个结果将被标记为错误,而uname -r将输出返回到STDOUT。

    问题

    虽然这个行为对我来说是合乎逻辑的(SSH客户端从pty看到的所有东西都是没有差异的输出)但我仍然不确定我是否会错过某些东西,并且有一个技巧可以分割这些输出。

0 个答案:

没有答案