简易Shell文件重定向实现遇阻塞问题求助
问题描述
自制简易Shell实现文件重定向功能时,输入./test1 > test2这类命令后,程序未执行命令就陷入阻塞,持续接收输入并写入test2文件;dup操作后的printf语句无输出,怀疑是文件描述符未正常关闭,但不清楚具体原因及解决方法。
相关代码片段
for(int i = 1; i < arg_no; i++){ if (strcmp(arg[i], ">") == 0){ fd = open(arg[i+1], O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP); if (fd < 0) { perror("open"); exit(1); } close(STDOUT_FILENO); if (dup(fd) < 0) { perror("dup"); exit(1); } close(fd); arg[i] = NULL; break; } else if(strcmp(arg[i], ">&") == 0){ fd = open(arg[i+1], O_WRONLY | O_CREAT, 0644); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); arg[i] = NULL; } else if(strcmp(arg[i], ">>") == 0){ fd = open(arg[i+1], O_WRONLY | O_CREAT | O_APPEND, 0644); dup2(fd, STDOUT_FILENO); close(fd); arg[i] = NULL; } else if(strcmp(arg[i] , ">>&") == 0){ fd = open(arg[i+1], O_WRONLY | O_CREAT | O_APPEND, 0644); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); arg[i] = NULL; } else if(strcmp(arg[i], "<") == 0){ fd = open(arg[i+1], O_RDONLY); dup2(fd, STDIN_FILENO); close(fd); arg[i] = NULL; } }
问题分析与解决办法
核心问题
- 重定向操作在父进程执行:直接在Shell主进程里修改了标准输入/输出的文件描述符,导致父进程自身的标准输出被重定向到
test2,后续的Shell交互输入都会被写入该文件,而非执行目标命令。 - 未清理重定向后的文件名参数:仅将重定向符号所在的
arg[i]设为NULL,但文件名对应的arg[i+1]仍在参数数组中,后续执行exec时会把文件名当成命令参数,导致命令执行异常。 close+dup的潜在风险:处理>时用close(STDOUT_FILENO)再dup(fd)的方式,不如dup2可靠——如果close和dup之间有其他操作占用了fd=1,会导致重定向失败。
解决步骤
- fork子进程执行命令与重定向:
重定向和命令执行必须放在子进程中完成,父进程仅负责等待子进程结束,避免修改父进程的文件描述符,保证Shell后续交互正常。核心逻辑示例:pid_t pid = fork(); if (pid == 0) { // 子进程中执行你写的重定向处理循环 // 执行目标命令 execvp(arg[0], arg); perror("execvp"); exit(1); } else if (pid > 0) { // 父进程等待子进程执行完毕 wait(NULL); } else { perror("fork"); } - 用dup2替代close+dup:
处理>时,将close(STDOUT_FILENO); dup(fd);替换为dup2(fd, STDOUT_FILENO);,直接将标准输出重定向到目标fd,更安全且代码更简洁。 - 清理文件名参数:
处理重定向时,除了arg[i] = NULL,还要将arg[i+1] = NULL,或者调整arg_no为i,避免文件名被当作命令参数传递给exec。 - 补全文件打开的错误判断:
所有open操作都要添加错误判断,比如处理<的场景:fd = open(arg[i+1], O_RDONLY); if (fd < 0) { perror("open"); exit(1); }
内容的提问来源于stack exchange,提问作者iknn
相关产品推荐
相关产品推荐

