GNU Readline额外提示符异常问题的修复方案咨询
问题描述
使用GNU Readline库编写类Shell程序时,遇到提示符处理Bug:通过^D退出here doc后,在主提示符按下^C,会意外出现额外提示符。复现步骤如下:
$ <<a # 开始here doc > # 用户输入^D退出here doc $ ^C # 用户在主提示符输入^C $ # 意外出现的额外提示符 $
简化复现代码:
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <readline/readline.h> volatile sig_atomic_t g_sig; void handle_sigint(int sig) { g_sig = sig; } int readline_hook(void) { if (g_sig == SIGINT) { rl_replace_line("", 0); rl_on_new_line(); rl_redisplay(); rl_done = 1; } return 0; } int main(void) { char *line; signal(SIGINT, handle_sigint); rl_event_hook = readline_hook; while (1) { g_sig = 0; line = readline("$ "); free(line); } }
修复方案
问题根源在于readline_hook中调用rl_redisplay()会触发Readline重复绘制提示符,后续循环再次调用readline("$ ")时就会出现额外提示符;同时原始信号处理逻辑的可靠性不足,终端状态未正确重置。
具体修复步骤
- 替换
signal为sigaction,保证信号处理的跨平台稳定性 - 在SIGINT处理函数中直接输出换行,替代
rl_redisplay(),避免重复绘制 - 移除
readline_hook中的rl_redisplay()调用,处理完信号后重置标记位 - 处理
readline()返回NULL的EOF场景(用户输入^D),手动输出换行维护终端状态
修改后的代码
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <readline/readline.h> volatile sig_atomic_t g_sig; void handle_sigint(int sig) { g_sig = sig; // 直接输出换行,避免Readline重复处理提示符 write(STDOUT_FILENO, "\n", 1); } int readline_hook(void) { if (g_sig == SIGINT) { rl_replace_line("", 0); rl_on_new_line(); rl_done = 1; // 重置信号标记,防止钩子重复触发 g_sig = 0; } return 0; } int main(void) { char *line; struct sigaction sa; sa.sa_handler = handle_sigint; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGINT, &sa, NULL); rl_event_hook = readline_hook; while (1) { g_sig = 0; line = readline("$ "); // 处理^D触发的EOF情况 if (line == NULL) { write(STDOUT_FILENO, "\n", 1); continue; } free(line); } }
内容的提问来源于stack exchange,提问作者kemizuki
相关产品推荐
相关产品推荐

