首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何从STDIN中“推迟”读取

如何从STDIN中“推迟”读取
EN

Stack Overflow用户
提问于 2018-09-24 21:36:07
回答 2查看 102关注 0票数 -1

在这个最小的工作示例中,我尝试执行以下操作:

通过指定为参数的文件或来自STDIN的

  1. 提示用户输入password
  2. Unmarshal JSON

源代码如下:

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.jsonecho 42 | go run main.go等)之外,一切都运行正常。

当我通过管道或将一些数据重定向到程序时,数据由密码提示符处理,而不是由JSON解码器部分处理。有没有办法在第一次提示输入密码时,只在处理传入的数据之后才输入密码?

我尝试detect if there's any data in STDIN来读取它并存储在一些临时的字节片中,但我找不到如何关闭/截断STDIN,所以它不会读取数据两次。

EN

回答 2

Stack Overflow用户

发布于 2018-09-27 03:25:18

在不对程序进行任何更改的情况下,您可以在json之前的标准输入中包含密码,例如(bash):{echo pass; cat data.json; } | goprogcat pass.txt data.json | goprog

有关更好的密码传递方法(例如环境或文件描述符),请查看sshpasshttps://linux.die.net/man/1/sshpass

您还可以缓冲所有标准输入,并在以后重用其内容(通过io.Reader)

重新设计您的应用程序逻辑,使其能够接受io.Reader作为要解组的数据源。

main()中,如果命令行上没有文件参数,则将os.Stdin传递给提到的函数,否则(尝试)打开文件并将其传递给解组函数。

注意:为了决定是否打印提示符,您可以使用类似于isatty的函数,该函数指示标准输入是否是交互式的:https://github.com/mattn/go-isatty

票数 1
EN

Stack Overflow用户

发布于 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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52480640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档