一、什么是shell
在计算机科学中,Shell俗称壳(用来区别于核),是指“为使用者提供操作界面”的软件(命令解析器)。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。
——《百度百科》
shell命令编辑器更多地用于unix/linux系统之中。
二、节选程序
int main()
{
/****************************声明程序中用到的函数*****************************/
int redirect(); /*重定向命令的处理函数*/
int pipel(); /*管道命令的处理函数*/
int get_line(); /*读取一行的函数*/
int is_founded(); /*查找命令的函数*/
void init_environ(); /*初始化环境变量的函数*/
void getenviron(); /*初始化查找路径的函数*/
void add_history(const char *string);/*调用上下方向键实现history命令的函数*/
void add_his_link(); /*记录history命令的函数*/
void history_cmd(); /*显示history命令的函数*/
void cd_cmd(); /*处理cd命令的函数*/
void jobs_cmd(); /*处理jobs命令的函数*/
void add_node(); /*向jobs命令的链表中增加节点函数*/
void del_node(); /*向jobs命令的链表中删除节点函数*/
void ctrl_z(); /*处理用户按下ctrl_z时的函数*/
void setflag(); /*将标志位置一的函数*/
void bg_cmd(); /*处理bg命令的函数*/
void fg_cmd(); /*处理fg命令的函数*/
init_environ(); /*初始化环境变量,将查找路径至于envpath[]中,
//初始化history,和jobs的头尾指针*/
while (1)
{
char c,*arg[20];
char hostName[60],path_string[40];
int i=0,j=0,k=0,is_pr=0,is_bg=0,input_len=0,path,pid=0,status=0,is_addpre=0,is_exe=0,is_absolute=0;
/**************************** 设置signal信号 *****************************/
struct sigaction action;//sigaction()函数用于改变进程接收到特定信号后的行为
action.sa_sigaction=del_node;//指向“新式”信号处理函数的指针
sigfillset(&action.sa_mask);//sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置
action.sa_flags=SA_SIGINFO;//sa_flags置为SA_SIGINFO(使用新式
sigaction(SIGCHLD,&action,NULL);
signal(SIGTSTP,ctrl_z);
/**************************** 打印提示符 *****************************/
path=get_current_dir_name();//获得当前路径名
gethostname(hostName,sizeof(hostName));//gethostname() : 返回本地主机的标准主机名
sprintf(path_string,"%s",path); //path路径
strcat(hostName,"@");
strcat(hostName,path_string);
strcat(hostName,"#"); //近似构成linux下的shell提示符
char * p =readline(hostName); //使用readline实现tab补全
if(strlen(p)==0)
continue;//当字符串p的长度为0时,即用户只是按下回车键,并没有输入任何字符,因此不需要对后面的操作进行处理
add_history(p); //调用<readline/history.h>头文件中的add_history函数实现上下方向键的history命令
/**************************** 获取用户输入 *****************************/
i=0;
while(p[i]==' ' || p[i]=='\t'|| p[i]==EOF)
i++; //跳过空格等无用信息
for(;i<strlen(p);i++){
if(p[i]=='\n')
continue; //输入为空时结束本次循环打印提示符
else {
buf[input_len++]=p[i];
}
}
buf[input_len]='\0'; //加上串结束符
if(buf[0]=='.'&&buf[1]=='/') //判断是否为./命令
is_exe=1;
if(buf[0]=='/')
is_absolute=1;
/*分配动态存储空间,将命令从缓存拷贝到input中*/
input=(char *) malloc(sizeof(char)*(input_len+1));
strcpy(input,buf);
add_his_link(input);
/**************************** 解析指令 *****************************/
/******************管道和重定向命令单独处理**************/
for (i=0,j=0,k=0;i<=input_len;i++){
if (input[i]=='<' || input[i]=='>' ||input[i]=='|'){
if (input[i]=='|'){
pipel(input,input_len);/*管道命令*/
//add_history(input);
free(input);
}
else{
//printf("is_addpre=%d,input[%d]=%c\n",is_addpre,i+1,input[i+1]);
if (input[i]=='>' && input[i+1]=='>')
is_addpre=1;
redirect(input,input_len,is_addpre);/*重定向命令*/
//add_history(input);
free(input);
}
is_pr=1;
break;
}
}
/********************** 普通命令 ***********************/
if (is_pr==1) continue;
if(is_addpre==1) continue;
for (i=0,j=0,k=0;i<=input_len;i++){
if (input[i]==' ' || input[i]=='\0'){
if (j==0) /*这个条件略去连在一起的多个空格*/
continue;
else{
buf[j++]='\0';
arg[k]=(char *) malloc(sizeof(char)*j);
strcpy(arg[k++],buf);/*将指令或参数拷到arg中*/
// printf("arg[%d]=%s\n",k-1,arg[k-1]);
j=0; /*准备取下一参数*/
}
}
else{
/*如果字符串最后是“&”,将后台命令标志置一*/
if (input[i]=='&' && input[i+1]=='\0'){
is_bg=1;
continue;
}
buf[j++]=input[i];
}
}
/********************** 内部命令的处理 ********************/
/*exit命令,退出*/
if (strcmp(arg[0],"exit")==0) {
//add_history(input);
printf("Shell exit.\n");
free(input);
break;
}
/*history命令,显示history数组中保存的历史命令*/
if (strcmp(arg[0],"history")==0) {
//add_history(input);
history_cmd();
free(input);
continue;
}
/*cd命令,改变当前路径*/
if (strcmp(arg[0],"cd")==0) {
//add_history(input);
for (i=3,j=0;i<=input_len;i++)/*获取路径*/
buf[j++]=input[i];
buf[j]='\0';
arg[1]=(char *) malloc(sizeof(char)*j);
strcpy(arg[1],buf);/*将路径保存到arg[1]中*/
cd_cmd(arg[1]);/*cd_cmd()函数,改变路径到指定路径*/
free(input);
continue;
}
/*jobs命令,显示现有工作*/
if (strcmp(arg[0],"jobs")==0) {
//add_history(input);
jobs_cmd();/*jobs_cmd()函数,遍历链表,显示所有工作*/
free(input);
continue;
}
/*bg命令,将作业放到后台执行*/
if (strcmp(arg[0],"bg")==0) {
//add_history(input);
/*获取制定的作业号,作业号在%后*/
for (i=0;i<=input_len;i++) {
if (input[i]=='%')
break;
}
i++;
for (;i<=input_len;i++)
buf[j++]=input[i];
buf[j]='\0';
arg[1]=(char *) malloc(sizeof(char)*j);
strcpy(arg[1],buf);/*将作业号保存在arg[1]中*/
// printf("arg[1]=%s\n",arg[1]);
bg_cmd(atoi(arg[1]));/*bg_cmd命令,将指定作业放到后台运行*/
free(input);
continue;
}
/*fg命令,将作业放到前台执行*/
if (strcmp(arg[0],"fg")==0) {
//add_history(input);
/*获取制定的作业号,作业号在%后*/
for (i=0;i<=input_len;i++) {
if (input[i]=='%')
break;
}
i++;
for (;i<=input_len;i++)
buf[j++]=input[i];
buf[j]='\0';
arg[1]=(char *) malloc(sizeof(char)*j);
strcpy(arg[1],buf);/*将作业号保存在arg[1]中*/
printf("%s\n",arg[1]);
fg_cmd(atoi(arg[1]));/*fg_cmd命令,将指定作业放到后台运行*/
free(input);
continue;
}
/**************************** 寻找命令文件 *****************************/
if (is_pr==0 ){/*非管道、重定向命令、非./、非绝对路径*/
/*在使用exec执行命令时,最后的参数必须是NULL指针,所以将其置空*/
arg[k]=(char *) malloc(sizeof(char));
arg[k]=NULL;
if(is_exe==0 && is_absolute==0) //./可执行文件名 命令的处理
{
if (is_founded(arg[0])==0){/*查找arg[0]中的命令是否存在*/
printf("This command is not founded!\n");
for (i=0;i<=k;i++)
free (arg[i]);
continue;}
}
}
//add_history(input);
/**************************** 执行命令 ******************************/
if ((pid=fork())==0){/*子进程*/
if (is_bg==1)/*若为后台命令,等待父进程增加节点*/
while (sig_flag==0)/*若sig_flag==0,等待父进程完成增加节点*/
/*等待父进程SIGUSR1信号,表示节点已加到链表中*/
signal(SIGUSR1,setflag);/*收到信号,setflag函数将sig_flag置一
,以跳出循环*/
sig_flag=0;/*置零,为下一命令作准备*/
if(is_exe==1 || is_absolute==1) //./可执行文件名 以及绝对路径命令的处理
{
if(execv(arg[0],arg)==-1)
perror("execv failed");
for (i=0;i<=k;i++)
free (arg[i]);
continue;
}
else if(execv(buf,arg)==-1)/*执行命令*/
perror("error");
}
else {/*父进程*/
pid1=pid;/*保存子进程进程号*/
if (is_bg==1) {/*后台命令*/
add_node(input,pid1);/*增加节点*/
kill(pid,SIGUSR1);/*向子进程发信号,表示节点已加进链表*/
pid1=0;/*pid1置零,为下一命令作准备*/
}
if (is_bg==0)
{
/*前台命令*/
waitpid(pid,&status,0);
//while(waitpid(pid,&status,WNOHANG)==0)
// {
// signal(SIGINT,dosig);
// }
}
}
if (is_bg==1) sleep(1);/*等待命令(如:ls &)输出后,再打印Shell提示符*/
for (i=0;i<k;i++)/*释放空间*/
free (arg[i]);
free(input);
}
return 0;
}
三、友情参考文献的链接
0.secret
Linux Shell脚本面试25个经典问答
https://www.cnblogs.com/gala1021/p/8519456.html
1.shell程序
1)C语言实现一个精简的shell
https://blog.youkuaiyun.com/lishichengyan/article/details/78193131
2)Linux C实现简单的shell
https://blog.youkuaiyun.com/wqx521/article/details/50894661
3)如何实现linux的Shell下按键盘的上下方向键就可以出现以前的命令?
https://bbs.youkuaiyun.com/topics/80237574
http://bbs.chinaunix.net/forum-viewthread-tid-667725.html
4)如何实现按下Tab键自动补全匹配的字符串并输出?
http://bbs.chinaunix.net/thread-656271-1-1.html
5)linux 读取键盘上下左右键小程序
https://blog.youkuaiyun.com/cean1024/article/details/72903069
6)shell命令解释器实验报告
http://www.doc88.com/p-8015468209269.html
7)linux的基本操作(shell 脚本的基础知识)
https://www.cnblogs.com/zhang-jun-jie/p/9266844.html
2.shell命令
1)Linux Shell常用shell命令
https://www.cnblogs.com/zhangziqiang/p/7478075.html
2)什么是bash shell的内建(build in)命令
https://blog.youkuaiyun.com/trochiluses/article/details/9094517
3)在linux下C语言实现对键盘事件的监听
https://blog.youkuaiyun.com/alangdangjia/article/details/27697721
4)Linux下键盘键值对应input event下的code值表
https://blog.youkuaiyun.com/cyf15238622067/article/details/78431709
5)Linux命令自己总结
https://www.cnblogs.com/200911/p/4012161.html
6)真正的Linux命令大全
https://wenku.baidu.com/view/3d63178a112de2bd960590c69ec3d5bbfd0adaed.html
7)在linux中使用getch()函数
https://www.xuebuyuan.com/3221739.html
8)linux环境下,清空history中记录的历史命令
https://www.cnblogs.com/chuanzhang053/p/9030834.html
9)linux 清空历史命令
https://www.cnblogs.com/hellojesson/p/9984518.html
10)Linux下的输入/输出重定向
https://www.cnblogs.com/fengkang1008/p/4652265.html
11)Linux中重定向
https://www.cnblogs.com/crazylqy/p/5820957.html
12)Linux的bg和fg命令简单介绍
https://www.cnblogs.com/oxspirt/p/8583307.html
13)Unix或Linux中&、jobs、fg、bg等命令的使用方法
https://blog.youkuaiyun.com/jimmy1357/article/details/46826133
14)linux:帮助命令help、man、info
https://www.cnblogs.com/kumata/p/8993914.html
15)Linux命令类型和执行顺序-type命令
https://blog.youkuaiyun.com/u010599211/article/details/85335864
16)Linux type命令的用法
https://blog.youkuaiyun.com/jiaxinhong/article/details/82826314
17)使用命令把前台和后台的进程互相转换
https://www.cnblogs.com/liu1026/p/8962440.html
18)Linux shell中运行可执行程序后加上&的作用
https://blog.youkuaiyun.com/oscarjulia/article/details/70272445
19)GNU Readline 库及编程简介
https://www.cnblogs.com/hazir/p/instruction_to_readline.html
20)readline库的简单使用
https://blog.youkuaiyun.com/xuancbm/article/details/81436681
本文介绍了操作系统中的shell,一种命令解析器,主要用于Unix/Linux系统。内容包括shell的概念、程序示例,以及一系列关于shell命令、键盘事件监听、输入输出重定向、进程管理等的资源链接,旨在帮助读者深入理解和实现shell编辑器。
901

被折叠的 条评论
为什么被折叠?



