
本文介绍在 linux/macos 等类 unix 系统中,使用 go 的 `bufio.newreader` 捕获多行用户输入,并将 `ctrl+s`(ASCII `dc3`,即 `x13`)设为输入终止符,同时保留换行符 `n` 作为输入内容的一部分;需预先禁用终端的 xon/xoff 流控。
在默认终端行为下,Ctrl+S 并不会被程序直接接收——它被内核级终端驱动解释为 XOFF 信号(暂停输出流),导致终端“假死”;同理,Ctrl+Q 对应 XON(恢复输出)。因此,若希望 go 程序将 Ctrl+S 视为普通输入字符(如结束符),必须先关闭终端的流控功能。
✅ 前置配置(仅需执行一次,推荐加入 shell 启动文件如 ~/.bashrc 或 ~/.zshrc):
stty -ixon
该命令禁用 IXON(即忽略 Ctrl+S/Ctrl+Q 的流控语义),使 Ctrl+S 以原始字节 x13 形式传递给应用程序。
⚠️ 注意:禁用后,你将失去终端冻结/解冻的快捷方式,但可通过 kill -STOP
完成配置后,Go 程序即可使用 ReadString(‘x13’) 直接监听 Ctrl+S:
package main import ( "bufio" "fmt" "os" ) func main() { reader := bufio.NewReader(os.Stdin) fmt.Println("Enter Text (press Ctrl+S to finish):") text, err := reader.ReadString('x13') // x13 = DC3 = Ctrl+S if err != nil { fmt.Fprintf(os.Stderr, "read error: %vn", err) return } // 注意:text 包含所有输入内容 + 末尾的 'x13' 字节 // 若不希望保留 Ctrl+S 字节,可用 strings.TrimSuffix(text, "x13") fmt.Print("Received input:n") fmt.Print(text) // 换行符 n 会原样保留并正常显示 }
? 关键说明:
- ReadString(‘x13’) 会持续读取(包括换行符 n),直到遇到第一个 Ctrl+S(即 x13)为止,且返回值 text 包含从开始到 x13 的全部字节(含中间所有 n);
- Ctrl+S 不会触发行缓冲刷新,因此无需 os.Stdin.Sync() 等额外操作;
- 此方案不适用于 windows 默认终端(cmd/PowerShell),因其不支持 stty 且 Ctrl+S 行为不同;windows 用户建议改用 golang.org/x/term 配合原始模式(raw mode)实现类似效果;
- 生产环境建议始终检查 err(示例中为简洁省略错误处理,实际不可忽略);
- 如需兼容性更强的交互式输入(支持编辑、历史、多键组合等),可考虑成熟库如 github.com/charmbracelet/bubbletea 或 github.com/muesli/termenv。
总结:通过 stty -ixon 解耦终端流控,并在 Go 中用 ReadString(‘x13’) 捕获 Ctrl+S,即可优雅实现“多行输入 + 自定义终止键”需求,兼顾简洁性与可控性。