Golang write input and get output from terminal process

只愿长相守 提交于 2020-01-11 04:06:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!