如何在ncurses中正确使用fork+exec避免输出混乱?
在ncurses中使用fork+exec避免输出混乱
问题描述
我查找了相关资料,但似乎没有关于在ncurses中使用fork+exec的内容。以下是我尝试编写的简单程序:
#include <ncurses.h> #include <unistd.h> #include <sys/wait.h> extern char **environ; int main(void){ initscr(); cbreak(); noecho(); pid_t child; mvprintw(0, 0, "press to continue"), refresh(); getch(); if (!(child = fork())) { def_prog_mode(), endwin(); if (execve("/bin/ksh", (char*[]){"ksh", NULL}, environ) < 0) { perror("execve failed"); } } else if (child > 0) { wait(&child); reset_prog_mode(), refresh(); mvprintw(0, 0, "Done!"), refresh(); getch(); endwin(); } else { endwin(); perror("fork failed"); } return 0; }
程序运行基本正常,但execve启动的进程输出全部显示在程序结束后的shell提示符下方。请问如何正确使用fork+exec以避免输出混乱?
解决方案
问题根源是ncurses接管终端后,子进程的标准IO没有正确关联到终端的原始交互状态。按以下方式修改代码即可解决:
- 在子进程中,除了调用
def_prog_mode()和endwin()恢复终端模式,还需要显式将标准输入、输出、错误重定向到/dev/tty,确保子进程直接与终端设备交互,而非继承ncurses处理后的文件描述符。 - 子进程执行失败时使用
_exit()而非exit(),避免触发父进程注册的清理钩子。
修改后的子进程代码片段:
if (!(child = fork())) { def_prog_mode(); endwin(); // 重定向标准IO到终端设备 int tty_fd = open("/dev/tty", O_RDWR); if (tty_fd != -1) { dup2(tty_fd, STDIN_FILENO); dup2(tty_fd, STDOUT_FILENO); dup2(tty_fd, STDERR_FILENO); if (tty_fd > 2) { close(tty_fd); } } if (execve("/bin/ksh", (char*[]){"ksh", NULL}, environ) < 0) { perror("execve failed"); _exit(1); } }
完整修改后的程序:
#include <ncurses.h> #include <unistd.h> #include <sys/wait.h> #include <fcntl.h> // 新增头文件,用于open的O_RDWR常量 extern char **environ; int main(void){ initscr(); cbreak(); noecho(); pid_t child; mvprintw(0, 0, "press to continue"), refresh(); getch(); if (!(child = fork())) { def_prog_mode(); endwin(); int tty_fd = open("/dev/tty", O_RDWR); if (tty_fd != -1) { dup2(tty_fd, STDIN_FILENO); dup2(tty_fd, STDOUT_FILENO); dup2(tty_fd, STDERR_FILENO); if (tty_fd > 2) close(tty_fd); } if (execve("/bin/ksh", (char*[]){"ksh", NULL}, environ) < 0) { perror("execve failed"); _exit(1); } } else if (child > 0) { wait(&child); reset_prog_mode(), refresh(); mvprintw(0, 0, "Done!"), refresh(); getch(); endwin(); } else { endwin(); perror("fork failed"); } return 0; }
修改后,子进程的输出会直接在终端显示,不会延迟到主程序结束后。
内容的提问来源于stack exchange,提问作者not_a_robot
相关产品推荐
相关产品推荐

