调用的程序通过os.exec失败如果运行

时间:2019-02-02 21:08:04

标签: go openssh

我不确定这是否是所调用程序的问题,还是该问题是由我调用程序的方式引起的。因此,我从源代码开始。

我需要从程序中调用ssh(如果您对我在下面提到它们的原因感兴趣),但是ssh会自动退出。

当我打电话ssh -v user@remotehost从壳此成功:

  • 在stderr的通缉调试输出被示
  • 要求我输入密码
  • 我可以看到远程主机外壳

但是当我在程序中执行相同操作时(myssh -v user@remotehost,只会发生这种情况:

  • 要求我输入密码

既没有显示stderr上的调试输出,也没有到达远程主机外壳。

这是我的源代码:

package main

import (
        "fmt"
        "log"
        "os"
        "os/exec"
)

func main() {
        params := os.Args[1:]
        fmt.Printf("passing this to ssh: %s\n", params)
        cmd := exec.Command("ssh", params...)
        err := cmd.Run()
        if err != nil {
                log.Fatal(err)
        }
}

原因是为什么我编写此代码:我使用Ansible调用ssh。我需要“操纵” Ansible传递给ssh的参数。到目前为止,我在OpenSSH和Ansible邮件列表中询问过,OpenSSH和Ansible中没有任何方法可以更改参数(对于其他参数,但我不需要的)。我得到并希望实现的最佳建议是为Ansible提供一个替代的ssh命令,使用它来接收和修改参数并将其传递给真实的ssh。

1 个答案:

答案 0 :(得分:1)

您是从Stdout捕获Stderrcmd吗?这是命令的各个输出发送到的位置。 Commit d327618的文档中有一个很好的例子。

在你的情况,你也想设置Stdin这样就可以例如通过密码。

下面是一个非常基本的例子,根据您的代码:

package main

import (
  "bytes"
  "fmt"
  "log"
  "os"
  "os/exec"
)

func main() {
  params := os.Args[1:]
  fmt.Println("Passing this to ssh: %s", params)

  var stdin  bytes.Buffer
  var stdout bytes.Buffer
  var stderr bytes.Bufer

  cmd := exec.Command("ssh", params...)
  cmd.Stdin  = &stdin
  cmd.Stdout = &stdout
  cmd.Stderr = &stderr

  if err := cmd.Run(); err != nil {
    log.Fatal(err)
  }

  fmt.Println("Stdout: %s", stdout.String())
  fmt.Println("stderr: %s", stderr.String())
}

由于stdinstdout,和stderr是所有bytes.Buffer S,则可以读取和由它们就像任何其他缓冲器写入。

您也可能要考虑使用golang.org/x/crypto/ssh包,它提供了一种天然SSH接口,用于转到而不是使用子过程。