【问题标题】:Check if there is something to read on STDIN in Golang检查 Golang 中的 STDIN 是否有需要阅读的内容
【发布时间】:2020-01-03 18:13:48
【问题描述】:

如果某些字符串通过管道传输到其 STDIN,我需要一个命令行实用程序来表现不同。这是一些最小的例子:

package main // file test.go

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    bytes, _ := ioutil.ReadAll(os.Stdin)

    if len(bytes) > 0 {
        fmt.Println("Something on STDIN: " + string(bytes))
    } else {
        fmt.Println("Nothing on STDIN")
    }
}

如果你这样称呼它就可以了:

echo foo | go run test.go

如果 test.go 在 STDIN 上没有任何内容的情况下被调用,事情就会卡在...

bytes, _ := ioutil.ReadAll(os.Stdin)

...等待EOF

我需要做什么才能让这一切顺利进行?

提前致谢!

【问题讨论】:

  • 您是否尝试使用 bufio.reader 或类似的东西包装标准输入?或者也许使用 peek 看看是否有什么要读的?
  • 阅读文档:ReadAll 一直持续到出现错误或 EOF,所以问问自己:从 stdin 读取是否有错误? EOF? (您可以在终端中发送 EOF,在 unix 上使用 control-D,在 windows 上发送其他内容)
  • @loreb 我阅读了文档。你描述的东西和我一样,没有提到任何新内容。
  • @Not_a_Golfer 我试试看,谢谢

标签: go


【解决方案1】:

我通过使用 os.ModeCharDevice 解决了这个问题:

stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
    fmt.Println("data is being piped to stdin")
} else {
    fmt.Println("stdin is from a terminal")
}

【讨论】:

  • 对此进行了测试,如果您从 /dev/null 管道标准输入(即 ./foo
  • 我比@NickCraig-Wood 更喜欢这个解决方案,因为它使用标准的 go 包。
【解决方案2】:

使用来自code.google.com/p/go.crypto/ssh/terminal(原为exp/terminal)的IsTerminal 函数或来自github.com/andrew-d/go-termutilIsatty 函数 这是一个更加集中的软件包。

如果 stdin 是终端/tty,那么您不会被管道传输,您可以做一些不同的事情。

这是一个例子

package main

import (
    "fmt"
    termutil "github.com/andrew-d/go-termutil"
    "io"
    "os"
)

func main() {
    if termutil.Isatty(os.Stdin.Fd()) {
        fmt.Println("Nothing on STDIN")
    } else {
        fmt.Println("Something on STDIN")
        io.Copy(os.Stdout, os.Stdin)
    }
}

测试

$ ./isatty 
Nothing on STDIN
$ echo "hello" | ./isatty 
Something on STDIN
hello
$ (sleep 1 ; echo "hello") | ./isatty 
Something on STDIN
hello

【讨论】:

  • 您能举个例子吗?
  • @sontags 示例提供!
【解决方案3】:

如果以上方法都不适合你,试试这个方法:

stat, err := os.Stdin.Stat()
if err != nil {
    return nil, fmt.Errorf("you have an error in stdin:%s", err)
}
if (stat.Mode() & os.ModeNamedPipe) == 0 {
    return nil, errors.New("you should pass smth to stdin")
}

它在 darwin (Mac OS) 和 linux (Ubuntu) 中都适用。

【讨论】:

  • $ go run sotest.go < sotest.go 结果为you should pass smth to stdinModeCharDevice 的答案符合预期。
【解决方案4】:

这样做:

package main // file test.go

import (
    "bufio"
"fmt"
    "os"
)

func main() {
    in := bufio.NewReader(os.Stdin)
    stats, err := os.Stdin.Stat()
    if err != nil {
        fmt.Println("file.Stat()", err)
    }

    if stats.Size() > 0 {
        in, _, err := in.ReadLine()
        if err != nil {
            fmt.Println("reader.ReadLine()", err)
        }
        fmt.Println("Something on STDIN: " + string(in))
    } else {
        fmt.Println("Nothing on STDIN")
    }
}

感谢@Kluyg!

【讨论】:

  • 这不起作用( sleep 1 ; echo "hello" ) | ./test,打印Nothing on STDIN。我认为您不会让这种方法可靠地工作。
猜你喜欢
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 2013-01-08
  • 2017-04-19
相关资源
最近更新 更多