Check if there is something to read on STDIN in Golang

匿名 (未验证) 提交于 2019-12-03 01:58:03

问题:

I need a command line utility to behave different if some string is piped into its STDIN. Here's some minimal example:

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")     } } 

This works fine if you call it like that:

echo foo | go run test.go 

If test.go is called without anything on STDIN, the thing stucks at...

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

... waiting for EOF.

What do I need to do to get this going?

Thanks in advance!

回答1:

I solved this by using 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") } 


回答2:

Use the IsTerminal function from code.google.com/p/go.crypto/ssh/terminal (which was exp/terminal) or the Isatty function from github.com/andrew-d/go-termutil which is a much more focussed package.

If stdin is a terminal/tty then you aren't being piped stuff and you can do something different.

Here is an example

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)     } } 

Testing

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


回答3:

If none of the above works for you, try this way:

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") } 

It worked for me in both darwin (Mac OS) and linux (Ubuntu).



回答4:

This does it:

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")     } } 

Thanks @Kluyg !



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!