可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 !