如何在go generate运行的脚本中实现等待用户输入的功能?
问题根因
go generate 执行时默认会将子进程的标准输入(stdin)重定向到空设备,因此所有读取os.Stdin的操作都会立即返回EOF,不会等待用户输入,这就是你现有代码无限循环的原因。
解决方案
方案1:直接读取终端设备实现等待输入(最贴合原需求)
不需要依赖默认的os.Stdin,直接打开当前关联的终端设备读取输入即可,支持跨平台,修改后的代码如下:
package main import ( "bufio" "log" "os" "runtime" ) func main() { for isFileOk := checkFile(); !isFileOk; { log.Println("File requires manual update.") log.Println("Hit [RETURN] when resolved.") // 打开当前终端设备,替代被重定向的stdin var tty *os.File var err error if runtime.GOOS == "windows" { tty, err = os.Open("CONIN$") } else { tty, err = os.Open("/dev/tty") } if err != nil { log.Fatalf("打开终端失败: %v", err) } scanner := bufio.NewScanner(tty) // 等待用户输入回车 scanner.Scan() tty.Close() isFileOk = checkFile() } } func checkFile() bool { return false }
修改后直接运行go generate generate.go即可正常等待用户按下回车再继续执行。
方案2:基于标记文件的无输入等待方案(兼容性更强)
如果不想处理终端设备的兼容逻辑,也可以用标记文件实现需求,不需要读取任何输入:
- 程序检测到文件需要更新时,提示用户更新完成后在当前目录创建名为
update.done的文件 - 程序循环检测该文件是否存在,检测到存在后自动删除标记文件,继续执行
代码示例:
package main import ( "log" "os" "time" ) const doneFlag = "./update.done" func main() { // 先清理可能残留的标记文件 os.Remove(doneFlag) for isFileOk := checkFile(); !isFileOk; { log.Println("File requires manual update.") log.Println("Create file [update.done] in current directory when resolved.") // 间隔1秒检测标记文件 time.Sleep(time.Second) if _, err := os.Stat(doneFlag); err == nil { os.Remove(doneFlag) break } } } func checkFile() bool { return false }
该方案完全不依赖标准输入,也适配没有终端的CI/CD场景。
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

