Linux编程实现一个简单的Shell
来源:互联网 发布:日系品牌女装推荐知乎 编辑:程序博客网 时间:2024/04/30 12:22
在linux中实现一个简单的命令解释程序,功能要求:
1)同时支持内部命令和外部命令,内部命令支持两个(cd、exit)
2)支持后台命令
首先解释一下上面的两个要求,实际上是三种情况:
1.如果是内部命令cd和exit,那么在父进程里直接分析执行
2.如果是外部命令,则创建一个子进程,再由子进程从path环境变量中查找相应的文件执行,此时shell会阻塞,等待子进程结束。
3.如果是后台命令,输入以&结束,它跟外部命令的最大区别是,后台命令创建了子进程后不需要调用wait(*status),也就是不用等待子进程结束,这样就变成了后台进程。
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/wait.h>#include <string.h>#include <errno.h>#define MAXLEN 80char cwd[MAXLEN];//当前工作目录char *prompt;char* parseCmd(char* cmd, char** argarr, int* argc){ enum states {S_START, S_INTOKEN, S_INQUOTES}; int numArgs = 0;//参数数目 int loop = 1;//循环标志 enum states state = S_START;//当前状态 int lastch; while(loop) { switch(state) { case S_START: if(*cmd == '"') { *argarr++ = cmd + 1; numArgs++; state = S_INQUOTES; } else if(*cmd == 0 || *cmd == ';') loop = 0; else if(*cmd <= ' ')//忽略ascii码表中的空格符及空格符前面的字符 *cmd = 0; else { *argarr++ = cmd; numArgs++; state = S_INTOKEN; } break; case S_INTOKEN: if(*cmd == 0 || *cmd == ';') loop = 0; else if(*cmd <= ' ') { *cmd = 0; state = S_START; } break; case S_INQUOTES: if(*cmd == 0) loop = 0; else if(*cmd == '"') { *cmd = 0; state = S_START; } break; } cmd++;//指向下一个字符 } *argarr = NULL;//最后一个参数指向空 if(argc != NULL) *argc = numArgs; lastch = cmd[-1]; cmd[-1] = 0; return lastch == ';' ? cmd : NULL;// 如果遇到分号则返回剩余的字符串作为下一条命令}int main(int argc, char** argv){ char cmd[80]; char* source = NULL; char* arg[20]; int statval; int numArgs; while(1) { if(source == NULL) { getcwd(cwd,MAXLEN); printf("%s$ ",cwd); //读取命令 if((source = gets(cmd)) == NULL) exit(0); } source = parseCmd(source, arg, &numArgs); if(numArgs == 0) continue; //是否退出程序 if(strcasecmp(arg[0], "exit") == 0) { exit(0);//不管exit后面是否还有参数,直接退出 } if(!strcmp(arg[0],"cd"))//切换父进程的工作目录 { chdir(arg[1]); continue; } if(!strcmp(arg[numArgs-1],"&"))//后台命令 { char* a[20];//临时变量 int k; for(k=0;k<numArgs-1;k++) { a[k] = malloc(strlen(arg[k]) + 1); strcpy(a[k],arg[k]); //printf("%s ", a[k]); } a[k] = NULL; if(fork() == 0) { if(execvp(a[0],a) == -1)// 执行失败 fprintf(stderr, "exec %s failed: %s\n",argv[0],strerror(errno)); exit(1);//退出子进程 } for(k=0;k<numArgs-1;k++);//释放内存 free(a[k]); continue; } //创建子进程执行命令 if(fork() == 0) { if(execvp(arg[0],arg) == -1)// 执行失败 fprintf(stderr, "exec %s failed: %s\n",argv[0],strerror(errno)); exit(1);//退出子进程 } wait(&statval); }}
下面看一下运行结果:
内部命令:
外部命令:
可以看到,此时shell发生阻塞。
后台命令:
可以看到,此时shell并没有阻塞。
下面说一下代码结构,代码主要分两块:
1.解析命令,将命令行参数进行解析保存。这里用到跟编译原理的词法分析器一样的有穷自动机进行分析,将单词从字符流中取出并保存。
2.执行命令。判断是三种命令中的哪一种,如果是内部命令,则在父进程中调用相应函数;如果是外部命令,则调用execlp()执行,并在父进程中调用wait()等待子进程结束;如果是后台命令,则在第二种情况下只去掉wait()函数,不用等待子进程结束。
罗嗦多一句,在实现后台命令时,如果关闭shell,也就是父进程结束,子进程也结束了。但是在系统的bash里面,调用后台命令后,就算关闭shell,子进程依然可以运行。我猜想是shell创建子进程后,将其父进程改为根进程或某个只要操作系统运行就不会死的进程,所以就算shell关闭子进程也不会结束。
0 0
- Linux编程实现一个简单的Shell
- 【Linux】实现一个简单的shell
- Linux.实现一个简单的shell
- 【Linux】实现一个简单的shell
- linux系统-shell编程-一个简单的shell程序
- 利用linux下的c语言编程来简单的实现一个shell功能实现!
- 实现一个简单的shell
- 一个简单的Linux Shell
- Linux 简单的shell实现
- Linux网络编程:一个简单的正向代理服务器的实现
- 关于一个简单的shell的实现
- Linu Shell 编程基础--一个简单的Shell脚本
- Linux下shell的简单编程
- Linux下shell的简单编程
- Linux下简单的shell编程(1)
- 一个简单地Shell-like 的实现
- 自主实现一个简单的shell
- Linux 编写一个简单的Shell脚本
- 空中网面试题
- linux 文件权限介绍
- Java读取UTF-8格式txt文件第一行出现乱码——问号“?”及解决
- c语言中形参和实参的区别
- Python并发编程的几篇文章
- Linux编程实现一个简单的Shell
- hdu 4292 Food 最大流
- 分享一些职业规划的思路
- 数制转换
- 关于c/c++中sizeof的资源
- 踏入软件行业一年,准备转行了
- POJ1042 钓鱼
- Add Subtitle (srt) to Video by using Ffmpeg
- MyBabitsXML中遍历以及插入语句返回ID