英文:
Check if there is something to read on STDIN in Golang
问题
我需要一个命令行实用程序,如果有一些字符串被输入到其标准输入(STDIN)中,它会有不同的行为。这里是一个简单的示例:
package main // 文件 test.go
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
bytes, _ := ioutil.ReadAll(os.Stdin)
if len(bytes) > 0 {
fmt.Println("STDIN 中有内容:" + string(bytes))
} else {
fmt.Println("STDIN 中没有内容")
}
}
如果像这样调用它,它可以正常工作:
echo foo | go run test.go
如果在没有任何内容输入到 STDIN 的情况下调用 test.go
,程序会在以下代码处停止:
bytes, _ := ioutil.ReadAll(os.Stdin)
等待 EOF
。
我需要做什么才能解决这个问题?
提前谢谢!
英文:
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
得分: 62
我使用os.ModeCharDevice解决了这个问题:
stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
fmt.Println("数据正在通过stdin进行传输")
} else {
fmt.Println("stdin来自终端")
}
英文:
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
得分: 20
使用code.google.com/p/go.crypto/ssh/terminal中的IsTerminal函数(以前是exp/terminal
)或github.com/andrew-d/go-termutil中的Isatty函数。
如果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
英文:
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"
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)
}
}
Testing
$ ./isatty
Nothing on STDIN
$ echo "hello" | ./isatty
Something on STDIN
hello
$ (sleep 1 ; echo "hello") | ./isatty
Something on STDIN
hello
答案3
得分: 3
如果以上方法都不适用于您,请尝试以下方式:
stat, err := os.Stdin.Stat()
if err != nil {
return nil, fmt.Errorf("stdin 出现错误:%s", err)
}
if (stat.Mode() & os.ModeNamedPipe) == 0 {
return nil, errors.New("您应该向 stdin 传递一些内容")
}
在我的测试中,这种方法在 darwin(Mac OS)和 linux(Ubuntu)上都有效。
英文:
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
得分: 0
这就是它的代码:
package main // 文件 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("STDIN 上的内容:", string(in))
} else {
fmt.Println("STDIN 上没有内容")
}
}
谢谢 @Kluyg!
英文:
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 !
答案5
得分: 0
这里的其他答案似乎在Windows上的Git Bash下不起作用,而Git Bash是GitHub Actions在Windows上的默认bash。来自golang.org/x/term的isTerminal
也似乎不起作用。
对我来说,使用https://github.com/mattn/go-isatty 在包括Windows上的Git Bash / cygwin / MinGW在内的各个平台上似乎都可以工作。
示例用法(playground链接):
func main() {
if isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) {
fmt.Println("stdin是终端,os.Stdin上没有内容")
return
}
// stdin可能有数据,也可能没有数据,但是由于它不是终端,
// 我们应该能够从中读取。
//
// 一些示例:
// echo foo | go run . # 我们可以从os.Stdin读取"foo"
// go run . < /dev/null # 我们可以读取os.Stdin,但它是空的
fmt.Println("stdin不是终端,我们可以读取它")
io.Copy(os.Stdout, os.Stdin)
}
请注意,这是回答“我可以从os.Stdin读取吗(可能是零长度)?”而不是“os.Stdin中是否有非空数据?”至少对于我的用例来说,第一种形式的问题是有用的,其中“零长度数据”是一种可以读取的输入数据类型。
我很想知道它是否对其他人不起作用(包括使用的平台)。
英文:
The other answers here did not seem to work under Git Bash on Windows, which is the default bash for GitHub Actions on Windows. isTerminal
from golang.org/x/term also did not seem to work.
For me, using https://github.com/mattn/go-isatty seems to work across platforms, including Git Bash / cygwin / MinGW on Windows.
Example usage (playground link):
func main() {
if isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) {
fmt.Println("stdin is terminal, nothing on os.Stdin")
return
}
// stdin might or might not have data, but given it is not a terminal,
// we should be able to read from it.
//
// Some examples:
// echo foo | go run . # we can read "foo" from os.Stdin
// go run . < /dev/null # we can read os.Stdin, but it is empty
fmt.Println("stdin is not a terminal and we can read it")
io.Copy(os.Stdout, os.Stdin)
}
Note that this is answering "Can I read from os.Stdin (which might be zero length)?", and not "Is there non-empty data in os.Stdin?". At least for my use case, the first form of the question is useful where "zero length data" is a type of input data that is OK to read.
I would be curious to hear if it does not work for someone else (including what platform).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论