写两次到同一个子进程golang

时间:2016-11-07 23:09:52

标签: go exec stdio

我有一个简单的scp函数,它只是scp cli工具的包装器。

type credential struct {
    username string
    password string
    host     string
    port     string
}

func scpFile(filepath, destpath string, c *credential) error {
    cmd := exec.Command("scp", filepath, c.username+"@"+c.host+":"+destpath)

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

    fmt.Println("done")
    return nil
}

这个工作正常现在我想添加在scp需要时输入SSH密码的功能。这就是我想出来的

func scpFile(filepath, destpath string, c *credential) error {
    cmd := exec.Command("scp", filepath, c.username+"@"+c.host+":"+destpath)
    stdin, err := cmd.StdinPipe()
    if err != nil {
        return err
    }
    defer stdin.Close()

    if err := cmd.Start(); err != nil {
        return err
    }

    io.WriteString(stdin, c.password+"\n")
    cmd.Wait()
    fmt.Println("done")
    return nil
}

这不起作用,因为密码提示只是挂在那里。在我写stdin之前,我尝试添加1秒钟的睡眠,以为我可能正在快速编写密码,但没有任何区别。

1 个答案:

答案 0 :(得分:0)

所以我能够找到一个解决方法,而不是尝试将密码发送到stdin我通过ssh会话创建一个ssh会话和scp文件。这是新的scpFile函数:

func scpFile(filePath, destinationPath string, session *ssh.Session) error {
    defer session.Close()

    f, err := os.Open(filePath)
    if err != nil {
        return err
    }
    defer f.Close()

    s, err := f.Stat()
    if err != nil {
        return err
    }

    go func() {
        w, _ := session.StdinPipe()
        defer w.Close()
        fmt.Fprintf(w, "C%#o %d %s\n", s.Mode().Perm(), s.Size(), path.Base(filePath))
        io.Copy(w, f)
        fmt.Fprint(w, "\x00")
    }()
    cmd := fmt.Sprintf("scp -t %s", destinationPath)
    if err := session.Run(cmd); err != nil {
        return err
    }
    return nil
}

这可能会更好,但主要的想法是