You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

简易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;
        }
    }
问题分析与解决办法

核心问题

  1. 重定向操作在父进程执行:直接在Shell主进程里修改了标准输入/输出的文件描述符,导致父进程自身的标准输出被重定向到test2,后续的Shell交互输入都会被写入该文件,而非执行目标命令。
  2. 未清理重定向后的文件名参数:仅将重定向符号所在的arg[i]设为NULL,但文件名对应的arg[i+1]仍在参数数组中,后续执行exec时会把文件名当成命令参数,导致命令执行异常。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 18:12:36