问题
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:
how to give subprocess a password and get stdout at the same time
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:
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:
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 (
"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
来源:https://stackoverflow.com/questions/23019890/golang-write-input-and-get-output-from-terminal-process