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
相关产品推荐
相关产品推荐

