C语言编写简易shell时execve()报No such file or directory错误
问题根因
你遇到的No such file or directory报错核心原因有3个:
getline()会把输入完成按回车产生的换行符\n一起读到缓冲区里,你以为传入的路径是/bin/ls,实际传入的是/bin/ls\n,系统找不到带换行后缀的可执行文件,自然报错。- 你给
execve()传的环境变量数组是空的,就算路径修对了,空环境也可能导致程序执行异常。 - 你没有调用
fork()创建子进程执行命令:execve会直接替换当前进程的代码段,只要执行成功,你的shell进程本身就会被替换成目标命令进程,命令运行完直接退出,永远不会回到循环打印下一个提示符,不符合shell的运行逻辑。
修复方案
按以下顺序修改代码即可:
- 读取到输入行后,第一时间去掉末尾的换行符,代码片段:
nread = getline(&line, &len, stdin); if (nread == -1) { perror("can't read command\n"); free(line); exit(95); } // 去掉末尾换行 if (nread > 0 && line[nread - 1] == '\n') { line[nread - 1] = '\0'; }
- 不要自定义空的env数组,引入全局环境变量表
extern char **environ;(头文件<unistd.h>里声明),直接把environ传给execve作为第三个参数即可。 - 执行命令前先
fork()子进程:子进程里调用execve执行命令,父进程调用wait()/waitpid()等待子进程执行结束,再回到循环等待下一个用户输入,不要在主进程里直接调用execve。 - 打印提示符后加
fflush(stdout),因为标准输出是行缓冲模式,没有换行符的话提示符不会立刻刷新显示,用户看不到输入提示。
修复后可运行的核心代码参考
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> extern char **environ; int main(void) { char *line = NULL, *argv[] = { NULL, NULL }; size_t len = 0; ssize_t nread; pid_t child_pid; int wstatus; do { printf("#cisfun$ "); fflush(stdout); nread = getline(&line, &len, stdin); if (nread == -1) { perror("can't read command\n"); free(line); exit(95); } // 去除末尾换行 if (nread > 0 && line[nread - 1] == '\n') { line[nread - 1] = '\0'; } if (strlen(line) == 0) { continue; } argv[0] = line; child_pid = fork(); if (child_pid == -1) { perror("fork error:"); continue; } if (child_pid == 0) { // 子进程执行命令 if (execve(line, argv, environ) == -1) { perror("Error:"); exit(1); } } else { // 父进程等待子进程结束 waitpid(child_pid, &wstatus, 0); } } while (1); free(line); return (0); }
补充:如果后续要支持带参数的命令(比如
ls -l),还需要额外对输入的line做分词切割,把参数依次填到argv数组里,保证argv最后一个元素是NULL即可。
内容的提问来源于stack exchange,提问作者Bayeroabdul
相关产品推荐
相关产品推荐

