В этом минимальном рабочем примере я пытаюсь сделать следующее:
- Запрашивать у пользователя пароль
- Unmarshal JSON либо из файлов, указанных в качестве аргументов, либо из STDIN
Вот исходный код:
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"os"
"syscall"
"golang.org/x/crypto/ssh/terminal"
)
const correctPassword = "secret"
func main() {
args := os.Args[1:]
var passwd string
for {
passwd = promptPassword()
if passwd == correctPassword {
log.Println("Correct password! Begin processing...")
break
}
log.Println("Incorrect password!")
}
if len(args) == 0 { // Read from stdin
log.Println("Reading from stdin")
dec := json.NewDecoder(os.Stdin)
for {
var v interface{}
if err := dec.Decode(&v); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
log.Printf("%#v", v)
}
}
for _, fileName := range args {
log.Println("Reading from", fileName)
f, err := os.Open(fileName)
if err != nil {
log.Println(err)
continue
}
defer f.Close()
dec := json.NewDecoder(f)
for {
var v interface{}
if err := dec.Decode(&v); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
log.Printf("%#v", v)
}
}
}
func promptPassword() (passwd string) {
for {
fmt.Fprintln(os.Stderr, "Enter password:")
b, _ := terminal.ReadPassword(int(syscall.Stdin))
passwd = string(b)
if passwd != "" {
break
}
}
return passwd
}
Все работает хорошо, за исключением случаев, когда уже подготовленные данные передаются по каналу или перенаправляются (например, go run main.go < mydata.json
, или echo 42 | go run main.go
и т. Д.).
Когда я передаю или перенаправляю некоторые данные в программу, данные обрабатываются паролем, а не частью JSON-декодера.Есть ли способ сначала запросить пароль и только после обработки входящих данных?
Я пытался обнаружить, есть ли какие-либо данные в STDIN , чтобы прочитать их и сохранить в некоторыхвременный байт, но я не могу найти, как закрыть / обрезать STDIN, поэтому он не будет читать данные дважды.