【问题标题】:Can a Go program read from the keyboard when stdin is something else?当 stdin 是其他东西时,Go 程序可以从键盘读取吗?
【发布时间】:2015-04-02 17:25:10
【问题描述】:

我有一个通过管道接受输入的 Go 进程。

tail -f something.foo |去运行 myprog.go

由于标准输入是管道的输出,我无法在 myprog.go 中找到读取键盘输入的方法。这可能吗?

我考虑在 myprog.go 中执行 tail 命令,但我想避免在 myprog.go 崩溃并且无法终止另一个进程时创建另一个进程。

【问题讨论】:

  • 这与 Go 无关。也许命名管道 FIFO(7) (man7.org/linux/man-pages/man7/fifo.7.html) 可以提供帮助?
  • 也许使用/dev/fd3 作为频道?没有尝试过,但类似的东西:tail ... 1>&3 | go run ... 然后打开 /dev/fd3 用于尾部输入和标准输入用于键盘。我不知道这是否有效,但我看不出它不应该的原因。

标签: go pipe stdin


【解决方案1】:

在 linux(以及一般的 POSIX)上,您可以打开 /dev/tty 以获取您进程的控制 tty 的输入。

func readStdin() {
    buf := make([]byte, 1024)
    for {
        n, err := os.Stdin.Read(buf)
        if err != nil && err != io.EOF {
            log.Fatal(err)
        }
        fmt.Print("FROM STDIN:", string(buf[:n]))
        if err == io.EOF {
            return
        }
    }
}

func main() {
    go readStdin()

    buf := make([]byte, 1024)
    tty, err := os.Open("/dev/tty")
    if err != nil {
        log.Fatal(err)
    }
    defer tty.Close()
    for {
        n, err := tty.Read(buf)
        if err != nil && err != io.EOF {
            log.Fatal(err)
        }
        fmt.Print("FROM TTY:", string(buf[:n]))
        if err == io.EOF {
            return
        }
    }
}

可以输出:

$ echo HELLO | ./tty_reader
FROM STDIN:HELLO
typing on my keyboard
FROM TTY:typing on my keyboard

【讨论】:

  • 不只是 Linux;其他 Unix 系统也可以正常工作。
【解决方案2】:

您可以使用 shell 创建一个管道来为您的程序提供输入,同时让 stdin 空闲用于其他事情。听起来有点像

go run myprog.go <(tail -f something.foo)

shell 将执行tail 并将它的标准输出重定向到一个新的fifo。您的程序接收 fifo 作为第一个参数,指向 /proc/self/fd/1234567

【讨论】:

  • 这是 非常 shell 特定的(仅限 bash?)。
猜你喜欢
  • 1970-01-01
  • 2011-08-14
  • 2011-04-13
  • 2012-03-18
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
相关资源
最近更新 更多