通过go exec.cmd运行SCP

时间:2018-06-30 10:47:28

标签: go ssh scp

我正在尝试通过golang的exec.cmd作为命令运行scp,因为可用于scp传输的非官方实现对我不起作用。 Scp一直执行到询问密码为止,然后我无法将数据写入stdin。可以将标准输入重定向到其他地方吗?

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会话传输二进制文件的方法? 预先感谢。

2 个答案:

答案 0 :(得分:1)

我假设您使用的是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”包更容易用于这种文件传输。您可以找到一个简单的示例here。请注意,不建议在客户端配置中将nil用于HostKeyCallback -如果绝对需要接受所有主机密钥,请使用HostKeyCallback: ssh.InsecureIgnoreHostKey()

答案 1 :(得分:0)

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

来自远程会话的标准输入不是这样,所以它将不起作用

标准的go golang.org/x/crypto/ssh软件包确实支持发送密码,因此可以解决。 scp is implemented as a server that is invoked by ssh,因此扩展现有的go ssh支持并不困难

但是,总是有一个基于外部程序的解决方法!如here所述, 这涉及使用<bean id="entityManagerFactory"程序