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

C语言编写简易shell执行命令报文件不存在错误如何解决

简易Shell报错问题修复

问题背景

尝试用C语言开发简易Shell,目标是输入可执行文件名即可运行对应程序,但代码运行时持续出现No such file or directory错误,原有实现代码如下:

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

/**
 * main - a super simple shell
 *
 * Return: always 0
 */
int main(void)
{
    char *command[] = {"", NULL};
    size_t len = 0;
    int flag = 1;
    pid_t child_process;
    int status;

    while (flag == 1)
    {
        printf("#fountain-shell$ ");
        getline(&command[0], &len, stdin);
        child_process = fork();
        if (child_process == -1)
        {
            perror("Error:");
            return (1);
        }
        if (child_process == 0)
        {
            if (execve(command[0], command, NULL) == -1)
            {
                perror("Error:");
            }
        }
        else
        {
            wait(&status);
            continue;
        }
    }
}

预期运行效果:

#cisfun$ /bin/ls
env-environ.c  exec    fork    mypid  ppid    printenv  promptc   shell    wait
env-main.c     exec.c  fork.c  pid.c  ppid.c  prompt    prompt.c  shell.c  wait.c
#cisfun$ ./ppid
5451
#cisfun$ ./ppid
5451
#cisfun$ ^C

错误原因

  • getline使用方式错误:代码中command[0]被初始化为指向字符串常量""的指针,字符串常量存储在只读内存段,且仅分配了1字节空间存储字符串结束符,既不允许写入内容,也没有足够空间存储用户输入,会触发未定义行为。
  • 未处理输入末尾的换行符:getline会将用户按下回车产生的\n字符一并存入输入缓冲区,比如输入ls回车后,缓冲区实际存储内容为"ls\n",和真实的可执行文件名不匹配,无法找到对应文件。
  • execve不支持自动路径搜索:execve要求传入可执行文件的完整路径(如/bin/ls、./ppid),如果仅传入文件名(如ls),只会在当前工作目录下查找,不会遍历系统PATH环境变量中的目录,因此无法找到系统命令。
  • 子进程逻辑漏洞:子进程调用execve失败后没有主动退出,会继续执行外层while循环,导致子进程也进入Shell交互逻辑,出现异常。
  • 输出缓冲区未刷新:标准输出默认是行缓冲模式,打印的提示符字符串末尾没有换行符,可能不会立即显示在终端上。

修正后代码

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

/**
 * main - a super simple shell
 *
 * Return: always 0
 */
int main(void)
{
    char *command = NULL;
    size_t len = 0;
    ssize_t nread;
    pid_t child_process;
    int status;

    while (1)
    {
        printf("#fountain-shell$ ");
        fflush(stdout); // 强制刷新输出缓冲区,保证提示符正常显示
        nread = getline(&command, &len, stdin);
        if (nread == -1) // 处理Ctrl+D退出场景
            break;
        
        // 移除输入末尾的换行符
        if (command[nread - 1] == '\n')
            command[nread - 1] = '\0';
        
        // 跳过空输入
        if (strlen(command) == 0)
            continue;

        char *argv[] = {command, NULL};
        child_process = fork();
        if (child_process == -1)
        {
            perror("fork error");
            free(command);
            exit(EXIT_FAILURE);
        }
        if (child_process == 0)
        {
            // 使用execvp,自动遍历PATH环境变量查找可执行文件
            if (execvp(command, argv) == -1)
            {
                perror("exec error");
                exit(EXIT_FAILURE); // 子进程执行失败后直接退出,避免进入主循环
            }
        }
        else
        {
            wait(&status);
        }
    }
    free(command); // 释放getline分配的内存
    return 0;
}

关键修正点说明

  • 调整getline传参:将输入字符指针初始化为NULL,交给getline自动分配足够内存存储输入,程序退出前主动释放分配的内存,避免内存泄漏。
  • 增加换行符处理逻辑:将getline读入的末尾换行符替换为字符串结束符,保证文件名匹配正确。
  • 替换执行函数:将execve替换为execvp,函数名中的p代表PATH,会自动遍历系统PATH环境变量中的所有目录查找可执行文件,无需输入完整路径即可运行系统命令。
  • 补全异常处理:增加空输入跳过、Ctrl+D正常退出、子进程执行失败后主动退出的逻辑,修复流程漏洞。
  • 增加输出缓冲区刷新:每次打印提示符后强制刷新标准输出,保证提示符正常显示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:57:19