📄 minish.c
字号:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <math.h>#include <signal.h>#include <stdlib.h>
#include "minish.h"
#define NO_PIPE -1
#define FD_READ 0
#define FD_WRITE 1
main()
{
/****************************声明程序中用到的函数*****************************/ int redirect(); /*重定向命令的处理函数*/ int pipel(); /*管道命令的处理函数*/ int getline(); /*读取一行的函数*/
int is_founded(); /*查找命令的函数*/ void init_environ(); /*初始化环境变量的函数*/
void getenviron(); /*初始化查找路径的函数*/
void add_history(); /*记录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];
int i=0,j=0,k=0,is_pr=0,is_bg=0,input_len=0,path,pid=0,status=0;
/**************************** 设置signal信号 *****************************/ struct sigaction action; action.sa_sigaction=del_node; sigfillset(&action.sa_mask); action.sa_flags=SA_SIGINFO;
sigaction(SIGCHLD,&action,NULL); signal(SIGTSTP,ctrl_z);
/**************************** 打印提示符 *****************************/
path=get_current_dir_name();
printf("qq@%s> ",path);
/**************************** 获取用户输入 *****************************/
while ((c=getchar())==' ' || c=='\t'|| c==EOF)
; /*跳过空格等无用信息*/
if (c=='\n')
continue; /*输入为空时结束本次循环打印提示符*/
while (c!='\n') {
buf[input_len++]=c;
c=getchar();
}
buf[input_len]='\0'; /*加上串结束符*/
/*分配动态存储空间,将命令从缓存拷贝到input中*/
input=(char *) malloc(sizeof(char)*(input_len+1));
strcpy(input,buf);
/**************************** 解析指令 *****************************/
/******************管道和重定向命令单独处理**************/
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{
redirect(input,input_len);/*重定向命令*/
add_history(input);
free(input);
}
is_pr=1;
break;
}
}
/********************** 普通命令 ***********************/
if (is_pr==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中*/
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("Bye bye!\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]中*/ 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]中*/ 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_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;/*置零,为下一命令作准备*/
execv(buf,arg);/*执行命令*/
}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); } if (is_bg==1) sleep(1);/*等待命令(如:ls &)输出后,再打印Shell提示符*/
for (i=0;i<k;i++)/*释放空间*/
free (arg[i]); free(input);
}
}
/**************************** 主程序完 *****************************/
/**************************** 重定向的处理 *****************************/
int redirect(char*in,int len)
{
char *argv[20],*filename[20];
pid_t pid;
int i,j,k,fd_in,fd_out,is_in=-1,is_out=-1,num=0;
int is_back=0,status=0;
/************************命令解析*************************/
/*argv[]用于存放命令和参数,filename用于存放重定向文件名,
is_in,is_out分别是重定向输入标记和输出标记*/
for (i=0,j=0,k=0;i<=len;i++) {
if (in[i]==' '||in[i]=='\t'||in[i]=='\0'||in[i]=='<'||in[i]=='>') {
if (in[i]=='>'||in[i]=='<') {
if (num<3){/*num存放重定向符号的出现次数*/
num++;
if (in[i]=='<')
is_in=num-1;/*存在重定向输入is_in置-1*/
else is_out=num-1;/*存在重定向输出is_out置-1*/
if (j>0 && num==1) {/*处理命令和重定向符号相连的问题*/
buf[j++]='\0';
argv[k]=(char *) malloc(sizeof(char)*j);
strcpy(argv[k],buf);
k++;
j=0;/*为读取下一命令或参数作准备*/
}
}else {
printf("Error command!\n");
return 0;
}
}
if (j==0)
continue;
else {
buf[j++]='\0';
if (num==0) {/*尚未遇到重定向符号,字符串是参数或命令*/
argv[k]=(char *) malloc(sizeof(char)*j);
strcpy(argv[k],buf);
k++;
j=0;
}else {/*遇到重定向符号,字符串是文件名*/
filename[status]=(char *) malloc(sizeof(char)*j);
strcpy(filename[status++],buf);
j=0;
}
}
}else {/*父进程*/
if (in[i]=='&' && in[i+1]=='\0') {/*是否为后台命令*/
is_back=1;
continue;
}
buf[j++]=in[i];
}
}
/*************************寻找命令文件*************************/
argv[k]=(char *) malloc(sizeof(char));
argv[k]=(char *) 0;/*最后一参数置空*/
if (is_founded(argv[0])==0) {/*查找命令文件*/
printf("This command is not founded!\n");
for (i=0;i<=k;i++)
free(argv[i]);
return 0;
}
/************************命令的执行**************************/
if ((pid=fork())==0) {
if (is_out!=-1) {/*存在输出重定向*/
if ((fd_out=open(filename[is_out],/*将文件描述符fd_out指向文件*/
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR))==-1) {
printf ("Can not open %s \n",filename[is_out]);
return 0;
}
}
if (is_in!=-1) {/*存在输入重定向*/
if ((fd_in=open(filename[is_in],/*将文件描述符fd_in指向文件*/
O_RDONLY,S_IRUSR|S_IWUSR))==-1) {
printf("Can not open %s \n",filename[is_in]);
return 0;
}
}
if (is_out!=-1) {
/*使用dup2函数将标准输出重定向到fd_out上,
这样原来输出到标准输出的内容,将输出到fd_out
所指向的文件。这就达到了重定向的目的*/
if (dup2(fd_out,STDOUT_FILENO)==-1) {
printf("Redirect standard out error!\n");
exit(1);
}
}
if (is_in!=-1) {
/*使用dup2函数将标准输入重定向到fd_in上,
这样原来从标准输入输入的内容,将从fd_in
所指向的文件输入。这就达到了重定向的目的*/
if (dup2(fd_in,STDIN_FILENO)==-1) {
printf("Redirect standard in error!\n");
exit(1);
}
}
execv(buf,argv);
}else {/*父进程*/
if (is_back==0)/*判断是否需要等待子进程的完成*/
waitpid(pid,&status,0);
}
/**************************释放空间*************************/
for (i=0;i<=k;i++)
free(argv[i]);
if (is_out!=-1) {
free(filename[is_out]);
close(fd_out);
}
if (is_in!=-1) {
free(filename[is_in]);
close(fd_in);
}
return 0;
}
/**************************** 管道的处理 *****************************/
int pipel(char *input,int len)
{
char *argv[10][30],*filename[0];
int i,j,k,is_bg=0;
int li_cmd=0,fd[10][1],pipe_in=-1,pipe_out=-1,flag=0;
pid_t pid;
/************************命令解析*************************/
/*此部分功能和结构与重定向时的命令解析相似*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -