Golang write input and get output from terminal process

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

Golang write input and get output from terminal process

问题

我有一个关于如何发送输入和接收终端子进程(如ssh)输出的问题。一个Python的例子可能是这样的:

https://stackoverflow.com/questions/17118239/how-to-give-subprocess-a-password-and-get-stdout-at-the-same-time?lq=1

我找不到一个类似的简单示例在Golang中如何工作。

在Golang中,我想要做类似这样的事情,但似乎不起作用:

cmd := exec.Command("ssh", "user@x.x.x.x")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
stdin, _ := cmd.StdinPipe()
stdin.Write([]byte("password\n"))
cmd.Run()

然而,我不确定如何在Go中做到这一点,因为每次执行这个ssh命令时,我只能得到输出。我无法自动从代码中输入我的密码。
有人有关于写入终端进程(如ssh)的示例吗?如果有,请分享一下。

英文:

I have a question regarding how to send input and receive output from a terminal subprocess such as ssh. An example in python would be something like this:

https://stackoverflow.com/questions/17118239/how-to-give-subprocess-a-password-and-get-stdout-at-the-same-time?lq=1

I cannot find a simple example in Golang that is similar how the above work.

In Golang I would want to do something like this but it does not seem to work:

    cmd := exec.Command("ssh", "user@x.x.x.x")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	stdin, _ := cmd.StdinPipe()
	stdin.Write([]byte("password\n"))
	cmd.Run()

However; I'm not sure how to do this in go because every time i exec this ssh command I am only able to get the output. I am unable to input my password automatically from code.
Does anyone have examples of writing to terminal processes such as ssh? If so, please share.

答案1

得分: 4

感谢上面的评论,我成功地使用密码获得了ssh访问权限。我使用了golang的ssh api库。我按照以下示例进行操作:

https://code.google.com/p/go/source/browse/ssh/example_test.go?repo=crypto

具体代码如下:

func ExampleDial() {
    // SSH客户端通过ClientConn表示。目前只支持“password”身份验证方法。
    //
    // 要与远程服务器进行身份验证,您必须通过ClientConfig的Auth字段传递至少一个AuthMethod的实现。
    config := &ClientConfig{
        User: "username",
        Auth: []AuthMethod{
            Password("yourpassword"),
        },
    }
    client, err := Dial("tcp", "yourserver.com:22", config)
    if err != nil {
        panic("Failed to dial: " + err.Error())
    }

    // 每个ClientConn可以支持多个交互式会话,由Session表示。
    session, err := client.NewSession()
    if err != nil {
        panic("Failed to create session: " + err.Error())
    }
    defer session.Close()

    // 创建Session后,您可以使用Run方法在远程端执行单个命令。
    var b bytes.Buffer
    session.Stdout = &b
    if err := session.Run("/usr/bin/whoami"); err != nil {
        panic("Failed to run: " + err.Error())
    }
    fmt.Println(b.String())
}

希望对你有帮助!

英文:

Thanks to the comments above, I was able to get ssh access working with a password. I used golang's ssh api library. It was fairly simple as I followed the examples from:

https://code.google.com/p/go/source/browse/ssh/example_test.go?repo=crypto

Specifically:

func ExampleDial() {
    // An SSH client is represented with a ClientConn. Currently only
    // the "password" authentication method is supported.
    //
    // To authenticate with the remote server you must pass at least one
    // implementation of AuthMethod via the Auth field in ClientConfig.
    config := &ClientConfig{
            User: "username",
            Auth: []AuthMethod{
                    Password("yourpassword"),
            },
    }
    client, err := Dial("tcp", "yourserver.com:22", config)
    if err != nil {
            panic("Failed to dial: " + err.Error())
    }

    // Each ClientConn can support multiple interactive sessions,
    // represented by a Session.
    session, err := client.NewSession()
    if err != nil {
            panic("Failed to create session: " + err.Error())
    }
    defer session.Close()

    // Once a Session is created, you can execute a single command on
    // the remote side using the Run method.
    var b bytes.Buffer
    session.Stdout = &b
    if err := session.Run("/usr/bin/whoami"); err != nil {
            panic("Failed to run: " + err.Error())
    }
    fmt.Println(b.String())
}

答案2

得分: 2

这是一个修改/完整版本的上面示例的链接:https://godoc.org/golang.org/x/crypto/ssh#example-Dial

首先通过go get golang.org/x/crypto/ssh获取terminal

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"strings"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

func main() {
	if len(os.Args) < 3 {
		usage := "\n./remote-ssh {host} {port}"
		fmt.Println(usage)
	} else {
		host := os.Args[1]
		port := os.Args[2]

		username, password := credentials()
		config := &ssh.ClientConfig{
			User: username,
			Auth: []ssh.AuthMethod{
				ssh.Password(password),
			},
		}
		connectingMsg := fmt.Sprintf("\nConnecting to %s:%v remote server...", host, port)
		fmt.Println(connectingMsg)

		hostAddress := strings.Join([]string{host, port}, ":")
		// fmt.Println("Host add %s ", hostAddress)
		client, err := ssh.Dial("tcp", hostAddress, config)
		if err != nil {
			panic("Failed to dial: " + err.Error())
		}

		for {
			session, err := client.NewSession()
			if err != nil {
				panic("Failed to create session: " + err.Error())
			}
			defer session.Close()

			// Once a Session is created, can execute a single command on remote side
			var cmd string
			str := "\nEnter command (e.g. /usr/bin/whoami OR enter 'exit' to return) : "
			fmt.Print(str)
			fmt.Scanf("%s", &cmd)
			if cmd == "exit" || cmd == "EXIT" {
				break
			}
			s := fmt.Sprintf("Wait for command '%s' run and response...", cmd)
			fmt.Println(s)

			var b bytes.Buffer
			session.Stdout = &b
			if err := session.Run(cmd); err != nil {
				panic("Failed to run: " + err.Error())
			}
			fmt.Println(b.String())
		}
	}
}

func credentials() (string, string) {
	reader := bufio.NewReader(os.Stdin)

	fmt.Print("Enter Username: ")
	username, _ := reader.ReadString('\n')

	fmt.Print("Enter Password: ")
	bytePassword, err := terminal.ReadPassword(0)
	if err != nil {
		panic(err)
	}
	password := string(bytePassword)

	return strings.TrimSpace(username), strings.TrimSpace(password)
}

链接:https://play.golang.org/p/4Ad1vKNXmI

英文:

This is a modified/complete version of above example https://godoc.org/golang.org/x/crypto/ssh#example-Dial

First get terminal package by go get golang.org/x/crypto/ssh

package main
import (
&quot;bufio&quot;
&quot;bytes&quot;
&quot;fmt&quot;
&quot;os&quot;
&quot;strings&quot;
&quot;golang.org/x/crypto/ssh&quot;
&quot;golang.org/x/crypto/ssh/terminal&quot;
)
func main() {
if len(os.Args) &lt; 3 {
usage := &quot;\n./remote-ssh {host} {port}&quot;
fmt.Println(usage)
} else {
host := os.Args[1]
port := os.Args[2]
username, password := credentials()
config := &amp;ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
}
connectingMsg := fmt.Sprintf(&quot;\nConnecting to %s:%v remote server...&quot;, host, port)
fmt.Println(connectingMsg)
hostAddress := strings.Join([]string{host, port}, &quot;:&quot;)
// fmt.Println(&quot;Host add %s &quot;, hostAddress)
client, err := ssh.Dial(&quot;tcp&quot;, hostAddress, config)
if err != nil {
panic(&quot;Failed to dial: &quot; + err.Error())
}
for {
session, err := client.NewSession()
if err != nil {
panic(&quot;Failed to create session: &quot; + err.Error())
}
defer session.Close()
// Once a Session is created, can execute a single command on remote side
var cmd string
str := &quot;\nEnter command (e.g. /usr/bin/whoami OR enter &#39;exit&#39; to return) : &quot;
fmt.Print(str)
fmt.Scanf(&quot;%s&quot;, &amp;cmd)
if cmd == &quot;exit&quot; || cmd == &quot;EXIT&quot; {
break
}
s := fmt.Sprintf(&quot;Wait for command &#39;%s&#39; run and response...&quot;, cmd)
fmt.Println(s)
var b bytes.Buffer
session.Stdout = &amp;b
if err := session.Run(cmd); err != nil {
panic(&quot;Failed to run: &quot; + err.Error())
}
fmt.Println(b.String())
}
}
}
func credentials() (string, string) {
reader := bufio.NewReader(os.Stdin)
fmt.Print(&quot;Enter Username: &quot;)
username, _ := reader.ReadString(&#39;\n&#39;)
fmt.Print(&quot;Enter Password: &quot;)
bytePassword, err := terminal.ReadPassword(0)
if err != nil {
panic(err)
}
password := string(bytePassword)
return strings.TrimSpace(username), strings.TrimSpace(password)
}

https://play.golang.org/p/4Ad1vKNXmI

huangapple
  • 本文由 发表于 2014年4月12日 02:18:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/23019890.html
匿名

发表评论

匿名网友

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

确定