在这个最小的工作示例中,我尝试执行以下操作:
通过指定为参数的文件或来自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解码器部分处理。有没有办法在第一次提示输入密码时,只在处理传入的数据之后才输入密码?
我尝试detect if there's any data in STDIN来读取它并存储在一些临时的字节片中,但我找不到如何关闭/截断STDIN,所以它不会读取数据两次。
发布于 2018-09-27 03:25:18
在不对程序进行任何更改的情况下,您可以在json之前的标准输入中包含密码,例如(bash):{echo pass; cat data.json; } | goprog
或cat pass.txt data.json | goprog
有关更好的密码传递方法(例如环境或文件描述符),请查看sshpass
:https://linux.die.net/man/1/sshpass
您还可以缓冲所有标准输入,并在以后重用其内容(通过io.Reader)
重新设计您的应用程序逻辑,使其能够接受io.Reader
作为要解组的数据源。
在main()
中,如果命令行上没有文件参数,则将os.Stdin
传递给提到的函数,否则(尝试)打开文件并将其传递给解组函数。
注意:为了决定是否打印提示符,您可以使用类似于isatty
的函数,该函数指示标准输入是否是交互式的:https://github.com/mattn/go-isatty
发布于 2018-09-25 03:21:04
您不能这样做,因为一旦完成内容的写入,shell就会关闭stdin文件描述符。
一旦stdin被关闭,你就不能重新打开它,这是由shell控制的。
检查此程序,以测试此行为
package main
import (
"fmt"
"io"
"os"
)
func main() {
io.Copy(os.Stdout, os.Stdin)
fmt.Println("done")
some := make([]byte, 100)
_, err := os.Stdin.Read(some)
fmt.Println(err)
fmt.Println(string(some))
}
输出将是
$ echo "some" | go run main.go
some
done
EOF
https://stackoverflow.com/questions/52480640
复制相似问题