2014-04-11 180 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