做电商网站需要花费多少钱,免费推广网,建设校园门户网站理由,app网站开发重庆shell从用户读入字符串“ls”#xff0c;shell建立一个新的进程#xff0c;然后在那个进程中运行ls程序并等待那个进程结束。然后shell读取新的一行输入#xff0c;建立一个新的进程#xff0c;在这个进程中运行程序#xff0c;并等待这个进程结束。所以要写一个shellshell建立一个新的进程然后在那个进程中运行ls程序并等待那个进程结束。然后shell读取新的一行输入建立一个新的进程在这个进程中运行程序并等待这个进程结束。所以要写一个shell需要循环以下过程 1. 获取命令行 2. 解析命令行 3. 建立一个子进程fork 4. 替换子进程execvp 5. 父进程等待子进程退出wait #include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include sys/types.h
#include sys/wait.h#define SIZE 1024
#define MAX_ARGC 64
#define SEP // 命令参数之间的分隔符// 全局变量
char *argv[MAX_ARGC]; // 用于存储解析后的命令行参数
char pwd[SIZE]; // 当前工作目录
char env[SIZE]; // for test
int lastcode 0; // 最后一个子进程的退出状态// 获取主机名
const char* HostName()
{char *hostname getenv(HOSTNAME); // 从环境变量中获取HOSTNAME if(hostname) return hostname; // 如果找到返回主机名else return None;// 否则返回None
}// 获取用户名
const char* UserName()
{char *username getenv(USER);if(username) return username; // 如果找到返回用户名else return None; // 否则返回None
}// 获取当前工作目录
const char *CurrentWorkDir()
{char *pwd getenv(PWD); // 应该是从环境变量中获取PWD if(pwd) return pwd; // 如果找到返回当前工作目录 else return None; // 否则返回None
}// 获取用户主目录
char *Home()
{return getenv(HOME); // 从环境变量中获取HOME
}// 与用户进行交互获取命令字符串
int Interactive(char out[], int size)
{// 输出提示符并获取用户输入的命令字符串ls -a -lprintf([%s%s %s]$ , UserName(), HostName(), CurrentWorkDir());fgets(out, size, stdin);// 从标准输入读取一行out[strlen(out)-1] 0; //\0, commandline是空串的情况?// 移除字符串末尾的换行符\n return strlen(out);// 返回命令字符串的长度不包括末尾的\0
}// 分割用户输入的命令字符串为参数数组
void Split(char in[])
{int i 0; argv[i] strtok(in, SEP); // ls -a -l// 使用空格作为分隔符分割字符串并将第一个参数存入argv[0] while(argv[i] strtok(NULL, SEP)); // 故意将 写成 // 继续分割并存储剩余参数// 下面的代码块试图修改参数列表以在ls命令后添加--colorif(strcmp(argv[0], ls) 0){argv[i-1] (char*)--color;// 这会覆盖最后一个参数argv[i] NULL;// 确保argv数组以NULL结尾 }
}// 执行命令
void Execute()
{pid_t id fork();// 创建一个新的子进程if(id 0){// 在子进程中执行命令 execvp(argv[0], argv);// 使用环境变量中的PATH来查找要执行的程序 exit(1);// 如果execvp失败例如找不到程序则退出子进程并返回1 }int status 0;pid_t rid waitpid(id, status, 0);// 在父进程中等待子进程结束if(rid id) lastcode WEXITSTATUS(status); // 如果子进程正常结束获取其退出状态并保存//printf(run done, rid: %d\n, rid);
}int BuildinCmd()
{int ret 0;// 检测 argv[0] 是否为 cd如果是则执行 cd 命令 // 1. 检测是否是内建命令, 是 1, 否 0if(strcmp(cd, argv[0]) 0){// 2. 执行// 标记为内建命令 ret 1;// 获取 cd 命令的参数要切换到的目录如果没有参数则默认为家目录 char *target argv[1]; //cd XXX or cdif(!target) target Home();// 如果没有指定目录则切换到用户家目录// 切换到目标目录chdir(target);// 获取当前工作目录并保存到 temp 变量中char temp[1024];getcwd(temp, 1024);// 构造新的环境变量 PWD并将其设置为当前工作目录 snprintf(pwd, SIZE, PWD%s, temp);putenv(pwd);}// 检测 argv[0] 是否为 export如果是则执行 export 命令else if(strcmp(export, argv[0]) 0){ret 1;// 如果有参数则将其设置为环境变量if(argv[1]){strcpy(env, argv[1]);putenv(env);}}// 检测 argv[0] 是否为 echo如果是则执行 echo 命令 else if(strcmp(echo, argv[0]) 0){ret 1;// 如果没有参数则输出一个换行符 if(argv[1] NULL) {printf(\n);}else{// 如果参数以 $ 开头则进行特殊处理 if(argv[1][0] $){// 如果参数是 $?则输出上一个命令的退出状态if(argv[1][1] ?){printf(%d\n, lastcode);lastcode 0;}else{// 否则获取环境变量并输出其值 char *e getenv(argv[1]1);if(e) printf(%s\n, e);}}else{// 如果参数不是以 $ 开头则直接输出该参数 printf(%s\n, argv[1]);}}}return ret;
}int main()
{while(1){char commandline[SIZE];// 1. 打印命令行提示符获取用户输入的命令字符串int n Interactive(commandline, SIZE);if(n 0) continue;// 2. 对命令行字符串进行切割Split(commandline);// 3. 处理内建命令n BuildinCmd();if(n) continue;// 4. 执行这个命令Execute();}// for(int i0; argv[i]; i)// {// printf(argv[%d]: %s\n, i, argv[i]);// }return 0;
}