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

自定义Shell开发:dup2()致子进程在execvp()前终止的问题排查

问题分析与解决方案

核心问题1:不必要的管道重定向引发阻塞

你当前的代码无论命令是否需要管道,都会强制将子进程的标准输出重定向到管道。比如执行sort input.txt时,sort的输出会被送到管道写端,但父进程只是等待子进程结束,并没有读取管道读端的内容。当管道缓冲区被填满后,子进程会因为无法继续写入而阻塞,看起来像是子进程提前终止,实际上是卡在了输出步骤(比如printf或execvp执行后的命令输出)。

核心问题2:RunSubCommand中的数组越界错误

在RunSubCommand的打印循环里,你错误地使用了args[i]而不是args[j]:

for(j=0;j<i;j++)
{
     printf("%s\n", args[i]); // 这里应该是args[j]
}

i已经是数组的末尾索引(指向NULL),访问args[i]会读取空指针,直接触发段错误导致子进程崩溃,自然无法执行到execvp。


修复后的代码示例

1. 区分管道场景与普通命令场景

只有当处理管道链中的命令时(比如前一个命令的输出作为后一个的输入),才创建管道并进行重定向。对于普通命令,跳过管道重定向逻辑:

// 示例:假设你有一个标志位is_piped,标记当前命令是否属于管道链
int is_piped = 0; // 根据实际解析逻辑设置,比如检测到|时设为1
int f2[2];
if (is_piped) {
    pipe(f2);
}

int retval2 = fork();
if(retval2 == 0)
{
    printf("IF statement\n");
    if(input_direct !=  STDIN_FILENO)
    {
         dup2(input_direct, STDIN_FILENO);
         close(input_direct);
     }
    
    // 仅在管道场景下重定向stdout到管道
    if (is_piped) {
        printf("statement before calling Dup2(f2[1])\n");
        dup2(f2[1] , STDOUT_FILENO);
        close(f2[0]);
        close(f2[1]);
    }
               
    printf("statement before calling RSC()\n");
    RunSubCommand(token, startindex, endindex);
               
}
else if(retval2 > 0)
{                  
    if (is_piped) {
        close(f2[1]);
        wait(NULL);
        input_direct = f2[0];  
    } else {
        wait(NULL);
        // 普通命令无需保留管道读端,清空input_direct或做对应处理
    }
}

2. 修复RunSubCommand的数组越界问题

void RunSubCommand(char ** token, int startindex, int endindex)
{
     printf("RunSubCommand Fucntion Call: \n");
     char * args[(endindex - startindex)+1];
     int i=0,j=0, end, start;
     start = startindex;
     end = endindex - startindex;
     while(i < end)
     {
          args[i] = token[start];
          i++;
          start++;
      }
     args[i] = NULL;
     printf("Printing args: \n");
     for(j=0;j<i;j++)
     {
          printf("%s\n", args[j]); // 修复为args[j]
     }
     execvp(args[0], args);
     perror("Error in executing EXECVP");
}

额外优化建议

  • 关闭未使用的文件描述符:父进程后续若不再使用input_direct,需手动关闭,避免资源泄漏;子进程中管道相关的描述符要确保全部关闭。
  • 规范错误提示:perror参数无需添加换行,它会自动追加,改成perror("Error in executing EXECVP")即可。

内容的提问来源于stack exchange,提问作者wiwi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 15:53:07