writing twice to the same sub process golang

huangapple go评论88阅读模式
英文:

writing twice to the same sub process golang

问题

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

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
}

这个函数目前运行良好,现在我想添加在需要时向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秒钟,以防我输入密码太快,但没有任何改变。

英文:

I have a simple scp function that is just a wrapper over the scp cli tool.

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
}

This works just fine now I want to add the capability of putting in a password the SSH if scp needs it. This is what I came up with

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
}

This does not work as the password prompt just hangs there. I tried adding a 1 second sleep before I re write to stdin thinking maybe I was writing the password to fast but did not make a difference.

答案1

得分: 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
}

这可能还可以改进,但主要思路已经在这里了。

英文:

So I was able to find a work around by instead of trying to send the password to stdin I create a ssh session and scp a file through the ssh session. Here is the new scpFile function:

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
}

This could probably be made better but the main idea is there

huangapple
  • 本文由 发表于 2016年11月8日 07:09:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/40476346.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定