运行 SCP via go exec.cmd

Running SCP via go exec.cmd

我正在尝试通过 golang 的 exec.cmd 运行 scp 作为命令,因为可用于 scp 传输的非官方实现对我不起作用。 Scp 执行直到它要求输入密码,然后我无法将数据写入标准输入。标准输入是否有可能被重定向到其他地方?

var cmd *exec.Cmd
if m.IsDir() {
    cmd = exec.Command("scp", "-r", src, user+"@"+client.Host+":"+dest)
} else {
    cmd = exec.Command("scp", src, user+"@"+client.Host+":"+dest)
}

cmdWriter, err := cmd.StdinPipe()
if err != nil {
    return err
}

err = cmd.Start()

if cred.Typ() == "PW" {
    cmdWriter.Write( []byte(cred.Data()+"\n") )
} else {
    log.Println( "credential typ not supported" )
}

err = cmd.Wait()
log.Println( "done" )
return err

将 cmd.Stdin 设置为 os.Stdin 可行,但当然我必须手动输入密码,这不是我想要的。 或者您总体上不会向 运行 scp 推荐这种方式吗?我能够在服务器上 运行 简单的 SSH 命令(使用 "golang.org/x/crypto/ssh")。有没有办法通过 SSH 会话传输二进制文件? 提前致谢。

scp 和 ssh 坚持从 tty(或伪 tty)读取密码

来自远程会话的标准输入不是这个,所以它不会工作

标准的 go golang.org/x/crypto/ssh package does support sending passwords so presumably has a work around. 所以扩展现有的 go ssh 支持可能并不困难

但是,总有一个基于外部程序的解决方法!正如所讨论的 here, 这涉及使用 sshpass 程序

我假设你在 Linux。如果您想从命令行向 scp 传递密码,最好的方法是使用 sshpass。它应该可以从主要 Linux 发行版的默认包存储库中安装,只需使用 aptyum 安装即可。语法是 sshpass -p [password] scp ...

在这里,我生成了一个 bash 会话,并从 StdinPipe:

向它发送命令
func main() { 
    cmd := exec.Command("bash")
    cmdWriter, _ := cmd.StdinPipe()
    cmd.Start()

    cmdString := fmt.Sprintf("sshpass -p %s scp -r %s %s@%s:%s", password, src, user, client, dest)

    cmdWriter.Write([]byte(cmdString + "\n"))
    cmdWriter.Write([]byte("exit"    + "\n"))

    cmd.Wait()
}

我忽略了错误并为简洁起见稍微简化了您的代码。


但是,"github.com/pkg/sftp" 软件包更易于用于此类文件传输。您可以找到一个如何使用它的简单示例 。请注意,在客户端配置中使用 nil 作为 HostKeyCallback 已被弃用 - 如果您绝对需要接受所有主机密钥,请使用 HostKeyCallback: ssh.InsecureIgnoreHostKey()