状況:
ユーザーが入力した内容をエコーせずstdin
に、コンソールからパスワード エントリを取得したい。Goの機能に匹敵するものはありますか?getpasswd
私が試したこと:
を使用してみsyscall.Read
ましたが、入力内容が反映されます。
以下は、それを実現するための最良の方法の 1 つです。最初にterm
パッケージを取得するgo get golang.org/x/term
package main
import (
"bufio"
"fmt"
"os"
"strings"
"syscall"
"golang.org/x/term"
)
func main() {
username, password, _ := credentials()
fmt.Printf("Username: %s, Password: %s\n", username, password)
}
func credentials() (string, string, error) {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter Username: ")
username, err := reader.ReadString('\n')
if err != nil {
return "", "", err
}
fmt.Print("Enter Password: ")
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
if err != nil {
return "", "", err
}
password := string(bytePassword)
return strings.TrimSpace(username), strings.TrimSpace(password), nil
}
#go-nuts メーリングリストでメールを見ました。非常に単純な go パッケージを作成して使用する人がいます。ここで見つけることができます: https://github.com/howeyc/gopass
それはそのようなものです:
package main
import "fmt"
import "github.com/howeyc/gopass"
func main() {
fmt.Printf("Password: ")
pass := gopass.GetPasswd()
// Do something with pass
}
これを行うには、execを実行stty -echo
してエコーをオフstty echo
にし、パスワードを読み取ってからオンに戻します。
これは、Go1.6.2 を使用して開発した便利なソリューションです。
次の標準パッケージのみを使用します: bufio
、、、および。より具体的には、およびを使用して stty を呼び出し、ターミナル エコーを無効/有効にします。fmt
os
strings
syscall
syscall.ForkExec()
syscall.Wait4()
Linux と BSD (Mac) でテストしました。Windows では動作しません。
// getPassword - Prompt for password. Use stty to disable echoing.
import ( "bufio"; "fmt"; "os"; "strings"; "syscall" )
func getPassword(prompt string) string {
fmt.Print(prompt)
// Common settings and variables for both stty calls.
attrs := syscall.ProcAttr{
Dir: "",
Env: []string{},
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
Sys: nil}
var ws syscall.WaitStatus
// Disable echoing.
pid, err := syscall.ForkExec(
"/bin/stty",
[]string{"stty", "-echo"},
&attrs)
if err != nil {
panic(err)
}
// Wait for the stty process to complete.
_, err = syscall.Wait4(pid, &ws, 0, nil)
if err != nil {
panic(err)
}
// Echo is disabled, now grab the data.
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
panic(err)
}
// Re-enable echo.
pid, err = syscall.ForkExec(
"/bin/stty",
[]string{"stty", "echo"},
&attrs)
if err != nil {
panic(err)
}
// Wait for the stty process to complete.
_, err = syscall.Wait4(pid, &ws, 0, nil)
if err != nil {
panic(err)
}
return strings.TrimSpace(text)
}
Go ForkExec() 関数を使用して stty を起動する必要があります。
package main
import (
os "os"
bufio "bufio"
fmt "fmt"
str "strings"
)
func main() {
fmt.Println();
if passwd, err := Getpasswd("Enter password: "); err == nil {
fmt.Printf("\n\nPassword: '%s'\n",passwd)
}
}
func Getpasswd(prompt string) (passwd string, err os.Error) {
fmt.Print(prompt);
const stty_arg0 = "/bin/stty";
stty_argv_e_off := []string{"stty","-echo"};
stty_argv_e_on := []string{"stty","echo"};
const exec_cwdir = "";
fd := []*os.File{os.Stdin,os.Stdout,os.Stderr};
pid, err := os.ForkExec(stty_arg0,stty_argv_e_off,nil,exec_cwdir,fd);
if err != nil {
return passwd, os.NewError(fmt.Sprintf("Failed turning off console echo for password entry:\n\t%s",err))
}
rd := bufio.NewReader(os.Stdin);
os.Wait(pid,0);
line, err := rd.ReadString('\n');
if err == nil {
passwd = str.TrimSpace(line)
} else {
err = os.NewError(fmt.Sprintf("Failed during password entry: %s",err))
}
pid, e := os.ForkExec(stty_arg0,stty_argv_e_on,nil,exec_cwdir,fd);
if e == nil {
os.Wait(pid,0)
} else if err == nil {
err = os.NewError(fmt.Sprintf("Failed turning on console echo post password entry:\n\t%s",e))
}
return passwd, err
}
https://github.com/peterh/linerパッケージPasswordPrompt
の機能を使用することもできます。
os.File オブジェクト (または os.Stdin 変数) から Read メソッドを使用して、必要な動作を取得できます。次のサンプル プログラムは、(リターン キーを押して終了する) テキスト行を読み取りますが、fmt.Printf 呼び出しまでエコーしません。
package main
import "fmt"
import "os"
func main() {
var input []byte = make( []byte, 100 );
os.Stdin.Read( input );
fmt.Printf( "%s", input );
}
より高度な動作が必要な場合は、おそらく Go C ラッパー ユーティリティを使用して、低レベルの API 呼び出し用のラッパーを作成する必要があります。