2014-04-11 125 views
1

我有一个关于如何发送输入和从终端子进程接收输出的问题,如ssh。在python一个例子是这样的:Golang写入输入并从终端进程获得输出

how to give subprocess a password and get stdout at the same time

我找不到Golang一个简单的例子,它类似于上述的工作原理。

在Golang我会想要做这样的事情,但它似乎并没有工作:

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

然而,我不知道如何去做这件事,因为每次我执行这个SSH命令,我只能得到输出。我无法从代码自动输入我的密码。 有没有人有写入终端进程的例子,如SSH?如果是这样,请分享。

+2

你不能用'ssh'很容易做到这一点,因为它会拒绝从'stdin'读取密码。请参阅http://stackoverflow.com/q/1340366。您的最佳选择似乎是生成密钥对并使用它进行身份验证。 –

+2

我曾尝试在Python中做到这一点。我只能使用[Paramiko](http://www.lag.net/paramiko/)工作。你应该试试[go.crypto/ssh](http://godoc.org/code.google.com/p/go.crypto/ssh)。 –

+0

你似乎知道如何处理一个子进程的stdin和stdout就好了。该问题不在你的代码中,但是由于ssh在检测到它没有在shell或tty中运行时具有不同的行为。你将不得不使用证书认证而不是密码。 –

回答

2

感谢上面的评论,我能够通过密码获得ssh访问权限。我使用了golang的ssh api库。这是相当简单的,因为我随后从实施例:

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

具体来说:

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()) 
} 
1

这是上述实施例的变形/完整版本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