#include "csapp.h" #define MAXARGS 128 /*本案例学习fork()函数建立进程,以及execve()函数加载并运行程序*/ //eval函数用于解析命令行并执行相关命令 void eval(char *cmdline) { char *argv[MAXARGS]; char buf[MAXLINE]; int bg; pid_t pid; strcpy(buf,cmdline); //复制字符串 bg=parseline(buf,argv);//bg为1或0 if(argv[0]==NULL) //参数为空,返回主函数 return; if(!builtin_command(argv)) { //返回0的情况 if((pid=fork())==0) { //新建子进程 if(execve(argv[0],argv,environ)<0) { //运行带有参数的可执行程序,若出现错误,则execve函数会返回负数,执行错误提示,并且退出该子进程 printf("%s:Command not found.\n",argv[0]); exit(0); } } if(!bg) { //当bg为0时,即输入命令不是空且结尾字符串不是&的情况 int status; if(waitpid(pid,&status,0)<0) //若等待子进程终止或退出时发生了错误,则返回-1,并且执行以下错误提示 printf("waitfg:waitpid error\n"); } else //当bg为1时,输出进程ID及命令行参数 printf("%d,%s",pid,cmdline); } return; } //builtin_command函数用于判断命令是否合法 //例如若命令行第一个字符串为quit,则表示正常退出父进程(主程序) //若第一个字符串为&,则返回1,否则返回0 //可以认为&开头表示该行命令为注释行,不用执行 int builtin_command(char **argv) { if(!strcmp(argv[0],"quit")) //quit键表示退出整个程序 exit(0); if(!strcmp(argv[0],"&")) //&开头则返回1 return 1; return 0; //一般情况下返回0 } //parseline函数用于读取命令行参数,并将参数返回至argv中 int parseline(char *buf,char **argv) { char *delim; int argc; int bg; buf[strlen(buf)-1]=‘ ‘; //将最后一位‘\0‘置为空格 while(*buf&&(*buf==‘ ‘)) //跳过开头部分的所有空格 buf++; argc=0; //用于计数(参数个数) while((delim=strchr(buf,‘ ‘))) { //strchr函数用于寻找字符在字符串中首次出现的位置,返回该位置指针 argv[argc++]=buf;//将单个参数存入argv指针当中 *delim=‘\0‘; buf=delim+1;//更新buf所指向的地址 while(*buf&&(*buf==‘ ‘)) //跳过空格 buf++; } argv[argc]=NULL; if(argc==0) //若参数个数为0,则返回1 return 1; if((bg=(*argv[argc-1]==‘&‘))!=0) //若参数命令行最后一个字符为&,将&置为NULL,并且返回1;否则返回0 argv[--argc]=NULL; return bg; } /*主函数入口*/ int main() { char cmdline[MAXLINE]; while(1) { printf("> "); fgets(cmdline,MAXLINE,stdin); //从终端读取输入 if(feof(stdin)) exit(0); eval(cmdline); //执行子程序 } }
运行示例
> ./main1.o acbc> quit
时间: 2024-10-14 04:52:34