检查Golang中的STDIN上是否有要读取的内容

son*_*ags 32 go

如果某个字符串通过管道连接到其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")
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您这样称呼它,这可以正常工作:

echo foo | go run test.go
Run Code Online (Sandbox Code Playgroud)

如果test.go在STDIN上没有任何东西的情况下调用,那么事情就会停留在...

bytes, _ := ioutil.ReadAll(os.Stdin)
Run Code Online (Sandbox Code Playgroud)

......等待EOF.

为了实现这一目标,我需要做些什么?

提前致谢!

ost*_*r.c 38

我通过使用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")
}
Run Code Online (Sandbox Code Playgroud)

  • 我比@ NickCraig-Wood更喜欢这个解决方案,因为它使用标准的go包. (3认同)

Nic*_*ood 14

使用IsTerminal从功能code.google.com/p/go.crypto/ssh/terminal(这是exp/terminal)或Isatty从功能github.com/andrew-d/go-termutil 这是一个更聚焦的包.

如果stdin是终端/ tty那么你就不是管道式的东西,你可以做一些与众不同的事情.

这是一个例子

package main

import (
    "fmt"
    "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)
    }
}
Run Code Online (Sandbox Code Playgroud)

测试

$ ./isatty 
Nothing on STDIN
$ echo "hello" | ./isatty 
Something on STDIN
hello
$ (sleep 1 ; echo "hello") | ./isatty 
Something on STDIN
hello
Run Code Online (Sandbox Code Playgroud)