我是Go的新手(就像在最后一天一样),我正在玩一个处理stdin数据的简单程序。我想做的是使得如果没有向stdin提供数据,那么程序将输出帮助屏幕然后退出。我遇到的问题是,当没有通过stdin提供数据时程序似乎无限期挂起。以下是该计划的简短示例和我的预期用法:
package main
import (
"fmt"
"bufio"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
str := scanner.Text()
fmt.Println(str)
}
}
Running with input:
go run test.go < lines.txt
line1
line2
line3
Running with no input:
go run test.go
我不提供输入的第二种情况是导致程序挂起的原因。通过文档阅读我不清楚我如何能够编写程序以便无限期地等待输入,而是在stdin上没有任何内容时中断。
答案 0 :(得分:3)
程序的行为与代码完全一致。代码说从stdin读取。可以通过重定向(如您所示)提供对stdin的输入。或者通过管道。或....或用户键入键盘。如果在最后一种情况下程序会在人类输入之前退出,那将是非常令人惊讶的。
一种常见的方法是执行类似(简化)的操作:
var in *os.File
var err error
switch name := flag.Arg(0); {
case name == "":
in = os.Stdin
default:
if in, err = os.Open(name); err != nil {
log.Fatal(err)
}
}
IE中。允许处理作为命令行参数给出的命名文件 - 但是当没有给程序提供文件名参数时,回退/默认为读取stdin。
这种方法可以很好地处理shell脚本,通过管道链接命令等等。
答案 1 :(得分:2)
对于你的用例来说,这可能有点拉伸,特别是如果你只是选择了go,但一般来说,你想要的行为可以通过使用带超时的select来模仿:
func scanForInput() chan string{
lines := make(chan string)
go func(){
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
lines <- scanner.Text()
}
close(lines)
}
return lines
}
func main(){
lines := scanForInput()
for {
select{
case line, closed := <- lines:
fmt.Prinln(line)
if closed {
return
}
case time.After(1 * time.Second):
printHelpMessage()
return
}
}
}
将它视为您下一个学习步骤的灵感。
PS:恩惠,我希望像语言一样: - )