实现一个自己的shell程序,这个程序有这些功能:解释执行命令,支持输入输出重定向,支持管道,后台运行

程序。当运行该程序后,它支持以下的命令格式:

1.单个命令,如:ls。2.带l到多个参数的命令,如ls -l。3.带一个输出重定向的命令。4.带一个输入重定向的

命令。5.带一个管道的命令。6.后台运行符&可加在各个命令的最后面。7.输入exit或logout退出myshell。

错误处理:1.输入错误的命令格式报错。2.输入不存在的命令报错。

程序主函数的流程图如下:

程序的各个函数的功能及说明:

(1)void print_prompt():该函数只是简单地打印myshell的提示符,即“myshell$”。

(2)void get_input(char *buf):获得一条用户输入的待执行命令,参数buf用于存放输入的命令。如果输入的

命令过长(大于256个字符),则终止程序。输入的命令以换行符'\n'作为结束标志。

(3)void explain_input(char *buf,int *argcount,char arglist[100][256]):解析buf中存放的命令,把每个

选项存放在arglist中。

(4)do_cmd(int argcount,char arglist[100][256]):执行arglist中存放的命令,arglist为待执行命令的参数

的个数。

(5)int find_command(char *command):功能是分别在当前目录下、/bin、/usr/bin目录下查找命令的可执行程

序。

下面是该程序的源代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#define normal 0        //一般的命令
#define out_redirect 1  //输出重定向
#define in_redirect 2   //输入重定向
#define have_pipe 3     //命令中有管道void print_prompt();         //打印提示符
void get_input(char*);       //得到输入的命令
void explain_input(char*,int*,char a[][256]);   //对输入命令进行解析
void do_cmd(int,char a[][256]); //执行命令
int find_command(char*);     //查找命令中的可执行程序int main(int argc,char *argv[])
{int i;int argcount= 0;char arglist[100][256];char *buf= NULL;char **arg= NULL;buf= (char*)malloc(256);if(buf == NULL){perror("malloc failed");exit(-1);}while(1){memset(buf,0,256);     //将buf所指向的空间清零
        print_prompt();get_input(buf);//若输入的命令为exit或logout则退出本程序if(strcmp(buf,"exit\n")== 0||strcmp(buf,"logout\n")== 0)break;for(i= 0;i< 100;i++){arglist[i][0]= '\0';}argcount= 0;explain_input(buf,&argcount,arglist);do_cmd(argcount,arglist);}if(buf!= NULL){free(buf);buf= NULL;}return 0;
}void print_prompt()
{printf("myshell$ ");
}//获取用户输入
void get_input(char *buf)
{int len= 0;int ch;ch= getchar();while(len< 256&&ch!= '\n'){buf[len++]= ch;ch= getchar();}if(len== 256){printf("command is too long\n");exit(-1);       //输入的命令过长则退出程序
    }buf[len]= '\n';len++;buf[len]= '\0';
}/*解析buf中的命令,将结果存入arglist中,命令以回车符号\n结束,如输入命令为*"ls -l /tmp",则arglist[0]、arglist[1]、arglist[2]分别为ls、-l、/tmp */
void explain_input(char *buf,int *argcount,char arglist[100][256])
{char *p= buf;char *q= buf;int number= 0;while(1){if(p[0]== '\n')break;if(p[0]== ' ')p++;else{q = p;number= 0;while((q[0]!= ' ')&&(q[0]!= '\n')){number++;q++;}strncpy(arglist[*argcount],p,number+ 1);arglist[*argcount][number]= '\0';*argcount= *argcount+ 1;p = q;}}
}void do_cmd(int argcount,char arglist[100][256])
{int flag= 0;int how= 0;            //用于指示命令中是否含有>、<、|int background= 0;     //标识命令中是否有后台运行标识符&int status;int i;int fd;char* arg[argcount+ 1];char* argnext[argcount+ 1];char* file;pid_t pid;//将命令取出for(i= 0;i< argcount;i++){arg[i]= (char*)arglist[i];}arg[argcount]= NULL;//查看命令行是否有后台运行符for(i= 0;i< argcount;i++){if(strncmp(arg[i],"&",1)== 0){if(i== argcount-1){background= 1;arg[argcount-1]= NULL;break;}else{printf("wrong command\n");return;}}}for(i= 0;arg[i]!= NULL;i++){if(strcmp(arg[i],">")== 0){flag++;how= out_redirect;if(arg[i+ 1]== NULL)flag++;}if(strcmp(arg[i],"<")== 0){flag++;how= in_redirect;if(i== 0)flag++;}if(strcmp(arg[i],"|")== 0){flag++;how= have_pipe;if(arg[i+ 1]== NULL)flag++;if(i== 0)flag++;}}/* flag大于1,说明命令中含有多个>,<,|符号,本程序是不支持这样的命令的,或者命令格式不对,如"ls -l /tmp >" */if(flag> 1){printf("wrong command\n");return;}if(how== out_redirect){//命令只含有一个输出重定向符号for(i= 0;arg[i]!= NULL;i++){if(strcmp(arg[i],">")== 0){file= arg[i+ 1];arg[i]= NULL;}}}if(how== in_redirect){//命令中只含有一个输入重定向符号for(i= 0;arg[i]!= NULL;i++){if(strcmp(arg[i],"<")== 0){file= arg[i+ 1];arg[i]= NULL;}}}if(how== have_pipe){/*命令只含有一个管道符号|,把管道符号后面的部分存入argnext中,管道后面的部分是一个可执行的shell命令 */for(i= 0;arg[i]!= NULL;i++){if(strcmp(arg[i],"|")== 0){arg[i]= NULL;int j;for(j= i+ 1;arg[j]!= NULL;j++){argnext[j-i-1]= arg[j];}argnext[j-i-1]= arg[j];break;}}}if((pid= fork())< 0){printf("fork error\n");return;}switch(how){case 0:/*pid为0说明是子进程,在子进程中执行输入的命令,输入的命令不含>、<、和| */if(pid== 0){if(!(find_command(arg[0]))){printf("%s : command not found\n",arg[0]);exit(0);}execvp(arg[0],arg);exit(0);}break;case 1://输入的命令中含有输出重定向符>if(pid== 0){if(!(find_command(arg[0]))){printf("%s : command not found\n",arg[0]);exit(0);}fd= open(file,O_RDWR|O_CREAT|O_TRUNC,0644);dup2(fd,1);execvp(arg[0],arg);exit(0);}break;case 2://输入的命令中含有输入重定向符<if(pid== 0){if(!(find_command(arg[0]))){printf("%s : command not found\n",arg[0]);exit(0);}fd= open(file,O_RDONLY);dup2(fd,0);execvp(arg[0],arg);exit(0);}break;case 3://输入的命令中含有管道符|if(pid== 0){int pid2;int status2;int fd2;if((pid2= fork())< 0){printf("fork2 error\n");return;}else if(pid2== 0){if(!(find_command(arg[0]))){printf("%s : command not found\n",arg[0]);exit(0);}fd2= open("/tmp/youdonotknowfile",O_WRONLY|O_CREAT|O_TRUNC,0644);dup2(fd2,1);execvp(arg[0],arg);exit(0);}if(waitpid(pid2,&status2,0)== -1)printf("wait for child process error\n");if(!(find_command(argnext[0]))){printf("%s : command not found\n",argnext[0]);exit(0);}fd2= open("/tmp/youdonotknowfile",O_RDONLY);dup2(fd2,0);execvp(argnext[0],argnext);if(remove("/tmp/youdonotknowfile"))printf("remove error\n");exit(0);}break;default:break;}//若命令中有&,表示后台执行,父进程直接返回,不等待子进程结束if(background== 1){printf("[process id %d]\n",pid);return;}//父进程等待子进程结束if(waitpid(pid,&status,0)== -1)printf("wait for child process error\n");
}//查找命令中的可执行程序
int find_command(char *command)
{DIR *dp;struct dirent *dirp;char *path[]= {"./","/bin","/usr/bin",NULL};//使当前目录下的程序可以运行,如命令"./fork"可以被正确解释和执行if(strncmp(command,"./",2)== 0)command= command+ 2;//分别在当前目录、/bin和/usr/bin目录查找要执行的程序int i= 0;while(path[i]!= NULL){if((dp= opendir(path[i]))== NULL)printf("can not open /bin \n");while((dirp= readdir(dp))!= NULL){if(strcmp(dirp->d_name,command)== 0){closedir(dp);return 1;}}closedir(dp);i++;}return 0;
}

转载于:https://www.cnblogs.com/XNQC1314/p/9196815.html

实现一个shell程序相关推荐

  1. Linux环境下编写一个shell程序,此程序的功能:随机生成一个1-100的数(答案)让用户猜

    题目:编写一个shell程序,此程序的功能:随机生成一个1-100的数(答案)让用户猜,如果用户猜的数大于答案,则提示大了,如果用户猜的数小于答案,则提示小了.当用户猜对时提示:猜对了. #! /bi ...

  2. 设计一个shell程序,在/userdata目录下建立50个目录,并对每个目录给754权限!

    设计一个Shell程序,在/userdata目录下建立50个目录,即user1-user50,并设置每个目录的权限,其中其他用户的权限为:读:文件所有者的权限为:读.写.执行:文件所有者所在组的权限为 ...

  3. Linux Shell 之 我的第一个Shell程序

    这里我首先会介绍一个Shell是什么,再介绍我的第一个Shell程序和从中总结的经验. 一.Shell是什么 在说我的这个Shell程序之前,还是先跟大家说说什么是Shell吧,相信Shell这个词大 ...

  4. Linux Shell编程(2)——第一个shell程序

    在最简单的情况下,脚本程序不过是存储在一个文件里的系统命令列表.这至少让你执行它 时不必重新按顺序键入相同功能的命令序列. 一个清空/var/log目录下的日志文件的脚本 # Cleanup # 必须 ...

  5. 为了忘却的纪念----开始从操就业的第一个SHELL程序

    来来往往,换了好多份工作,最近开始学习LINUX SHELL,写代码还要追溯到N多年了,那时写过一些JSP的代码,都是基于WEB类型开发的java,现在几乎把java都忘光了,却开始对linux的sh ...

  6. 设计一个Shell程序,在/userdata目录下建立50个目录,即user1~user50,

    #!/bin/bash a=1 while [ a -le 50 ] do if [ -d /userdata ] then mkdir -p /userdata/user$a else mkdir ...

  7. linux执行python不打印_在Python中执行shell程序而不打印到屏幕

    有没有一种方法可以让我从Python执行一个shell程序,它将输出打印到屏幕上,然后将它的输出读入变量而不在屏幕上显示任何内容?在 这听起来有点令人困惑,所以也许我可以用一个例子来解释它.在 假设我 ...

  8. Linux shell程序一

    设计一个Shell程序,在/$HONE/test目录下建立50个目录,即user1-user50, 并设置每个目录的权限,其中其他用户的权限为:读:文件所有者的权限为: 读.写.执行:文件所有者所在组 ...

  9. linux编写运行shell程序,Linux的Shell编程运行Shell程序的方法有哪些呢?

    用户可以用任何编辑程序来编写Shell程序.因为Shell程序是解释执行的,所以不需要编译成目的程序.按照Shell编程的惯例,以 bash为例,程序的第一行一般为"#!/bin/bash& ...

最新文章

  1. AI发展进入2.0时代!英特尔在落地中总结4大经验、分享7个案例
  2. 利用文件锁控制程序的执行
  3. springboot 参数校验详解
  4. 因为我的名字特殊大家都是用异样的眼光在看着我 04
  5. 有关性能测试结果的几点分析原则
  6. Android中文API(122) —— AudioRecord
  7. 【Java SE:抽象类】抽象类的引出与深入理解
  8. TIOBE 9 月编程语言:C++ 突起、Java 流行度下降
  9. ant ftp get nullpointerException
  10. Mysql DBA 20天速成教程
  11. 数据结构-单链表LNode,*LinkList
  12. Android hook微信 apk 实时获取微信聊天消息记录
  13. php radio是什么意思,radio是什么意思_radio在线翻译_英语_读音_用法_例句_海词词典...
  14. 利用PS的磁性套索工具进行抠图
  15. 使用Xamarin实现跨平台移动应用开发(转载)
  16. 为什么win10只有一个账户而此电脑C盘“其他人员”却占用空间呢?
  17. 专题训练二 搜索进阶 HDU - 3085 Nightmare Ⅱ (双向BFS + 曼哈顿距离)
  18. 土木工程考研和计算机考研哪个,土木工程考研还是就业
  19. 百度网盘怎么用迅雷下载文件?
  20. 『2021语言与智能技术竞赛』-机器阅读理解任务基线系统详解

热门文章

  1. 个人简历中计算机应用能力,年中计算机应用专业个人简历模板.docx
  2. 11 User Space, Kernel Space, and the System Call API(用户空间,核空间,系统api)
  3. linux firewalld
  4. 3.8 激活函数的导数
  5. 2.10 m 个样本的梯度下降
  6. 线性代数 矩阵消元与回代
  7. freecplus框架简介
  8. php扇形分布图,使用php绘制扇形分布图
  9. 微机计算机硬件技术实用教程知识点,微机接口技术实用教程1.ppt
  10. linux 安装nodejs8,CentOS 安装NodeJS V8.0.0的方法