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

C语言Shell模拟程序测试求助:模拟终端输入与输出验证问题

问题分析与解决方案

测试代码无法工作的原因

你的test.c存在多个关键问题:

  • 进程间通信逻辑错误:调用system("./shell")后,./shell会进入死循环等待输入,导致测试程序卡在这一步,永远不会执行后面的system("ls -l")。而且system("ls -l")是启动独立进程,和运行中的./shell没有任何交互,根本无法把命令输入到你的shell程序中。
  • 重定向的作用范围误解:你在test.c中用freopen修改的是测试进程自己的stdin/stdout,虽然system("./shell")启动的子进程会继承这些重定向,但如果input.txt为空,./shell会因fgets阻塞等待输入,无法继续执行。
  • 断言逻辑完全错误:ls -l的输出包含文件权限、所有者、大小、修改时间等完整信息,绝非你断言的"shell.c \n shell",直接用strcmp对比必然失败。
  • 字符串未正确终止:fread读取的内容不会自动添加\0终止符,strcmp访问时会出现未定义行为,可能导致程序崩溃或错误判断。

正确的测试方案

方案1:使用管道与shell进程交互(推荐)

通过fork+pipe创建管道,直接控制shell的输入和捕获输出,无需依赖文件:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int main() {
    int shell_stdin[2], shell_stdout[2];
    // 创建输入管道(测试程序写,shell读)
    pipe(shell_stdin);
    // 创建输出管道(shell写,测试程序读)
    pipe(shell_stdout);

    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:启动shell
        // 重定向stdin到管道读端
        dup2(shell_stdin[0], STDIN_FILENO);
        // 重定向stdout到管道写端
        dup2(shell_stdout[1], STDOUT_FILENO);
        // 关闭无用的管道端
        close(shell_stdin[1]);
        close(shell_stdout[0]);
        // 执行shell程序
        execl("./shell", "./shell", NULL);
        perror("exec shell failed");
        exit(1);
    } else {
        // 父进程:测试逻辑
        // 关闭无用的管道端
        close(shell_stdin[0]);
        close(shell_stdout[1]);

        // 向shell发送命令(注意要加换行,因为shell用fgets读取)
        const char* cmd = "ls -l\nquit\n";
        write(shell_stdin[1], cmd, strlen(cmd));
        close(shell_stdin[1]);

        // 读取shell的输出
        char output[4096] = {0};
        ssize_t n = read(shell_stdout[0], output, sizeof(output)-1);
        close(shell_stdout[0]);

        // 等待shell进程退出
        waitpid(pid, NULL, 0);

        // 验证输出:这里不直接对比完整ls输出(因为时间等会变),而是检查是否包含关键文件名
        assert(strstr(output, "shell.c") != NULL);
        assert(strstr(output, "test.c") != NULL);

        printf("Test passed!\n");
    }
    return 0;
}

方案2:使用文件重定向批量测试

如果需要批量测试多个命令,可以预先准备输入文件和预期输出:

  1. 创建test_input.txt,内容为:
ls -l
quit
  1. 编写测试程序:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // 执行shell,重定向输入输出到文件
    system("./shell < test_input.txt > test_output.txt");

    // 读取输出文件
    FILE* fp = fopen("test_output.txt", "r");
    assert(fp != NULL);
    char output[4096] = {0};
    fread(output, sizeof(output)-1, 1, fp);
    fclose(fp);

    // 验证关键内容
    assert(strstr(output, "shell.c") != NULL);
    assert(strstr(output, "test.c") != NULL);

    // 清理临时文件
    remove("test_output.txt");

    printf("Test passed!\n");
    return 0;
}

额外注意事项

  • 测试ls -l这类输出受环境影响的命令时,不要直接对比完整字符串,而是检查关键标识(如文件名),或者在临时目录中创建固定文件进行测试,避免因文件修改时间、权限等变化导致测试失败。
  • 你的shell.c本身存在缺陷:每次循环都会创建管道和fork,但没有等待子进程退出,会产生僵尸进程;另外read(fildes[0], buf, 1024)可能无法读取ls -l的完整输出(如果输出超过1024字节),需要循环读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 21:07:04