福建省建设职业注册资格管理中心网站,wordpress媒体管理插件,加强网站建设的建议,金华官方网站建设bash就是命令行解释器#xff0c;就是Linux操作系统让我们看到的#xff0c;与用户进行交互的一种外壳#xff08;shell#xff09;#xff0c;当然了bash也是一个进程#xff0c;它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进…bash就是命令行解释器就是Linux操作系统让我们看到的与用户进行交互的一种外壳shell当然了bash也是一个进程它有时候就是通过创建子进程来执行我们输入的命令的。这无疑就离不开我们上篇博客所说的进程程序替换就是让子进程去替换我们的命令进程知道了它的原理我们就可以试着自己写一个bash进程。
我们可以大体上对于整个过程来细分一下 1.bash就是先打印命令行提示符就是下面这个东西获取用户输入的命令 命令行提示符由 [用户名主机名 路径]# 这些构成 2.对于用户输入的字符串进行分割成命令 3.执行这个命令 其实大体上就是这三步下面还有很多的细节问题我们遇到再说 我们目前写的这个代码的结果是 为什么打印了两个换行我们了解一下fgets这个函数 因为fgets会读入一个换行就是我们敲完abc后的换行它是不应该有的我们要给它去掉 这样就可以把换行改成0了。
因为bash就是一只在等待用户输入指令所以我们要把我们的程序写成一个循环。
还有一个问题就是当我们什么都不输入直接回车时我们其实就没必要在执行下边了直接回到循环最开始就可以于是我们可以做一个判断就是如果输入的命令的长度为0那么就直接回到循环最开始处这里的长度可以让Interactive的返回值来给。
下一步就是对于字符串进行分割
我们分割的话函数可以将收到的字符串分割后放到一个全局变量中方便后续的使用我们C语言有一个分割字符串的函数叫strtok 分割完了之后我们就可以开始执行命令了就是让子进程执行父进程等待。我们这里先是一些普通的需要子进程去执行的命令因为有的命令需要父进程去执行比如cd需要父进程去切换路径子进程是不行的 那么截止到现在我们的程序已经可以像bash一样处理一些命令了但是还不够因为有一些内建命令就是需要父进程去执行的 这些命令我们要在代码被子进程执行前先行判断如果是内建命令那么让父进程去执行否则再让子进程去执行
我们这里先以cd命令为例如果判断出来了用户就是要输入cd命令如果后边什么都没有那么默认是回到家目录如果有那就chdir到那个目录并且不要忘记命令行提示符可是一直通过环境变量PWD来打印我们当前所在目录的所以我们还要通过putenv把PWD环境变量改一下它默认是会覆盖的。
之后我们要知道export也是一个内建命令export的作用是给自己设置一个环境变量如果给子进程设置那显然是不合理的所以我们也需要处理一下。
下一个就是echo我们的echo通常会有这么几种用法
1.echo后什么都不加
2.后加$?表示打印最近一次进程的退出码
3.后随便打印一串字符
4.后加$环境变量就打印环境变量的内容 下面是所有的代码有不足的可以添加 1 #define _XOPEN_SOURCE 2 #includestdio.h3 #includestdlib.h4 #includestring.h5 #includeunistd.h6 #includesys/types.h7 #includesys/wait.h8 #includestdlib.h9 #define SIZE 102410 #define MAX_ARGC 30//最大命令行字符串个数11 #define SEP //设置分隔符为空格12 char*argv[MAX_ARGC];13 int lastcode;//最近一次进程退出码14 int Interactive(char commandline[],int size)15 {16 printf([%s%s %s]$ ,getenv(USER),getenv(HOSTNAME),getenv(PWD));17 fgets(commandline,size,stdin);18 commandline[strlen(commandline)-1]\0;19 return strlen(commandline);20 }21 void Splitstr(char commandline[])22 {23 int i0;24 argv[i]strtok(commandline,SEP);25 while(argv[i]strtok(NULL,SEP));26 if(strcmp(ls,argv[0])0)27 {28 argv[i-1]--color;29 argv[i]NULL;30 }31 }32 void Execute()33 { 34 if(strcmp(ll,argv[0])0!argv[1])//特别处理ll35 {36 argv[0]ls;37 argv[1]-l;38 }39 pid_t idfork();40 if(id0)41 {42 execvp(argv[0],argv);43 printf(mybash: );44 for(int i0;argv[i];i)printf(%s ,argv[i]);45 printf(: not found your command\n);46 exit(2);47 }48 int status0;49 pid_t ridwaitpid(id,status,0);50 if(rid0)lastcodeWEXITSTATUS(status);51 }52 int Bulidincmd()53 {54 int ret0;55 if(strcmp(cd,argv[0])0)56 {57 ret1;58 char*targetargv[1];59 if(!target)targetgetenv(HOME);60 chdir(target);61 char tmp[SIZE];62 snprintf(tmp,SIZE,PWD%s,target);63 putenv(tmp); 64 }65 else if(strcmp(export,argv[0])0)66 {67 ret1;68 if(argv[1])69 {70 char tmp[SIZE];71 strncpy(tmp,argv[1]1,strlen(argv[1])-2);72 putenv(tmp);73 }74 }75 else if(strcmp(echo,argv[0])0)76 {77 ret1;78 if(argv[1]argv[1][0]$)79 {80 if(argv[1][1]?!argv[2])81 {82 printf(%d\n,lastcode);83 lastcode0;84 }85 else86 {87 char* tmpgetenv(argv[1]1); 88 if(tmp)printf(%s\n,tmp);89 }90 }91 else92 {93 for(int i1;argv[i];i)printf(%s ,argv[i]);94 printf(\n);95 }96 }97 lastcode0;98 return ret;99 }100 int main()101 {102 while(1)103 {104 char commandline[SIZE];105 //打印命令行提示符获取用户输入的命令字符串106 int nInteractive(commandline,SIZE);107 if(n0)continue;108 //分割字符串成命令行参数109 Splitstr(commandline);110 //处理内建命令111 nBulidincmd();112 if(n1)continue;113 //执行命令114 Execute(); 115 }116 return 0;117 }