
本文介绍在 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: %v\n", 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,即可优雅实现“多行输入 + 自定义终止键”需求,兼顾简洁性与可控性。










