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

自制Shell中ls/pwd命令异常问题排查求助

问题分析与修复方案

你的自制Shell核心问题出在命令解析逻辑完全没被调用,再加上几个小bug共同导致了ls和pwd的异常。咱们一步步拆解解决:

核心问题:用户输入未被解析到参数数组

你写了parsowanie函数来拆分命令行参数,但在main里读完用户输入的co_chcesz后,完全没调用这个函数!这导致argv数组一直是初始化的全0值,execvp拿到的是空参数,自然触发各种错误:

  • 对于ls:空参数让它误以为你要访问空路径,所以报cannot access ''
  • 对于pwd:错误的参数格式让它认为你传了无效的非选项参数,报ignoring non-option arguments

其他需要修复的小问题

  1. 未初始化的循环变量
    初始while(strcmp(co_chcesz,"exit\n"))时,co_chcesz是栈上的垃圾值,会导致不可预测的循环行为,需要先初始化它。

  2. waitpid的位置错误
    你把waitpid放在了子进程的分支里,但execvp成功后会直接替换子进程的地址空间,这段代码根本不会执行。而且子进程不该等待自己,waitpid必须放在父进程中。

  3. fgets缓冲区大小不匹配
    co_chcesz的大小是500,但你调用fgets(co_chcesz,1000,stdin),存在缓冲区溢出风险,应该用sizeof(co_chcesz)作为输入长度限制。

  4. 参数列表终止符不规范
    parsowanie函数最后用*argv = '\0';标记参数结束,虽然在C里'\0'等价于NULL指针,但直接用NULL更清晰规范。

修复后的完整代码

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

void parsowanie(char *line, char **argv) {
    while (*line != '\0') {
        // 跳过空白字符,用'\0'分隔参数
        while (*line == ' ' || *line == '\n'|| *line == '\t' ) 
            *line++ = '\0';
        // 记录当前参数的起始地址
        *argv++ = line;
        // 移动到下一个空白字符
        while (*line != '\0' && *line!= ' ' && *line != '\t' && *line != '\n') 
            line++;
    }
    // 用NULL标记参数列表结束(规范写法)
    *argv = NULL;
}

int main() {
    printf("MicroShell\nAutor:Amadeusz Lewandowski\n");
    char co_chcesz[500], cwd[500], login[50];
    char *argv[1000];
    pid_t pid;
    int status;

    // 初始化输入缓冲区,避免第一次strcmp读取垃圾值
    co_chcesz[0] = '\0';

    while(strcmp(co_chcesz,"exit\n") != 0) {
        sleep(1);
        getcwd(cwd, sizeof(cwd));
        getlogin_r(login, sizeof(login));
        printf("[%s:%s]\n$ ", login, cwd);
        
        // 读取用户输入,使用正确的缓冲区大小
        if (fgets(co_chcesz, sizeof(co_chcesz), stdin) == NULL) {
            // 处理EOF情况(比如Ctrl+D)
            break;
        }

        // 关键:调用解析函数,把输入拆分成argv参数数组
        parsowanie(co_chcesz, argv);

        // 如果用户只输入了空白,直接跳过循环
        if (argv[0] == NULL) {
            continue;
        }

        // 内置命令help单独处理,无需fork子进程
        if (strcmp(argv[0], "help") == 0) {
            printf("autor to miranda orange\n");
            continue;
        }

        pid = fork();
        if (pid == 0) {
            // 子进程:执行外部命令
            if (execvp(argv[0], argv) < 0) {
                perror("The following error occurred");
                printf("Value of errno:%d\n", errno);
                // 子进程执行失败必须退出,避免继续运行shell逻辑
                exit(EXIT_FAILURE);
            }
        } else if (pid > 0) {
            // 父进程:等待子进程执行完成
            waitpid(pid, &status, 0);
        } else {
            // 处理fork失败的情况
            perror("fork failed");
        }
    }
    return 0;
}

修复后验证

  • 输入ls:会正确解析参数,execvp调用正常的ls命令,列出当前目录内容
  • 输入pwd:正确调用pwd,不再报非选项参数错误
  • help内置命令和exit退出逻辑都能正常工作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 11:57:36