操作系统实验三——Shell实验(MSH)
实验内容:你的任务是实现⼀个在 Linux 系统下运⾏的简单 Shell,它能够实现如下功能:运⾏带参数的命令重定向输⼊输出(仅实现 < 与 > 即可)建⽴多级连接的双向管道,实现 | 左侧的标准输出传递给右侧作为其标准输⼊能够响应 Linux 中的信号,即当执⾏命令的进程收到 SIGINT 时会被杀死,⽽ Shell 本身不会被杀死其余的 Shell 特性不需要实现。以下是示例(这⾥
·
实验内容:
你的任务是实现⼀个在 Linux 系统下运⾏的简单 Shell,它能够实现如下功能:
- 运⾏带参数的命令
- 重定向输⼊输出(仅实现 < 与 > 即可)
- 建⽴多级连接的双向管道,实现 | 左侧的标准输出传递给右侧作为其标准输⼊
- 能够响应 Linux 中的信号,即当执⾏命令的进程收到 SIGINT 时会被杀死,⽽ Shell 本身不会被杀死
其余的 Shell 特性不需要实现。以下是示例(这⾥的 # 是命令提示符,类似于 bash 中的 $ )。
# echo hello there
hello there
# echo something > file.txt
# cat file.txt
something
# cat file.txt | wc
1 1 10
# echo echo hello | ./msh
hello
# # #
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<fcntl.h>
pid_t parentpid,childpid;
// 进程⾃定义的键盘中断信号处理函数
typedef void (*sighandler_t) (int); void sigcat()
{
if(getpid()==parentpid)
kill(childpid,SIGINT);
}
//解析字符串
int get_order(char *buf,char**argv)
{
int argc=0;
int flag=0;
int len=strlen(buf);
for(int i=0;i<len;i++)
{
if(buf[i]!=' '&&flag==0)
{
argv[argc++]=buf+i;
flag=1;
}
else if(buf[i]==' ')
{
flag=0;
buf[i]=0;
}
}
argv[argc]=NULL;
//for(int i=0;i<argc;i++)printf("%s\n",argv[i]); return argc;
}
//执行无管道的指令
void solve1(char *cmd)
{
char *argv[1024];
int argc=get_order(cmd,argv);
char *infile=NULL,*outfile=NULL; //记录文件名
int inflag=0,outflag=0;//标记是否有重定向
int targc=argc;//用来记录'<'或'>'的前一个位置
for(int i=0;i<argc;i++)
{
if(strcmp(argv[i],"<")==0)
{
if(i+1==argc)
{
printf("File name does nat exist.\n");
exit(1);
}
else{
infile=argv[++i];
inflag=1;
if(targc==argc)targc=i-1;
}
}
if(strcmp(argv[i],">")==0)
{
if(i+1==argc){
printf("File name does nat exist.\n");
exit(1);
}
else{
outfile=argv[++i];
outflag=1;
if(targc==argc)targc=i-1;
}
}
}
//处理重定向输入的目标文件不存在的情况
if(inflag==1)
{
FILE *fp=fopen(infile,"r");
if(fp==NULL)
{
printf("The input file not exist.\n");
exit(1);
}
fclose(fp);
}
//for(int i=0;i<argc;i++)printf("%s\n",argv[i]);
childpid=fork();
if(childpid<0)
{
printf("create process failed!\n");
exit(1);
}
else if(childpid==0)
{
if(inflag==1)
{//在分配⽂件描述符的时候会选择最⼩的未被分配的描述符
close(0); //关闭了0文件标识符,下面open的时刻就会把0文件标识符与文件关联
if(open(infile,O_RDONLY)!=0)
{
fprintf(stderr,"testsh:open!=0\n");
exit(-1);
}
}
if(outflag==1)
{
close(1);
if(open(outfile,O_WRONLY|O_CREAT|O_TRUNC,0777)!=1)
{
fprintf(stderr,"testsh:open!=1\n");
exit(-1);
}
}
char *temp[1024];
for(int i=0;i<targc;i++)temp[i]=argv[i];
temp[targc]=NULL;
execvp(temp[0],temp);
}
else{
int status;
waitpid(childpid,&status,0);
}
}
//处理包含管道的指令
void solve(char *cmd)
{
//无管道指令
if(strstr(cmd,"|")==NULL)
{
solve1(cmd);
return;
}
char *now;
char *next=NULL;
now =strtok_r(cmd,"|",&next); //根据'|'符号,切割字符串
if(*next==0){
printf("The end need a filename after |.\n");
exit(1);
}
int pipe1[2];
if(pipe(pipe1)<0){
printf("create pipe failed.\n");
exit(1);
}
childpid=fork();
if(childpid<0){
printf("create fork failed.\n");
exit(1);
}
else if(childpid==0)
{
close(pipe1[0]);
dup2(pipe1[1],1); //将文件标识符1和管道关联
solve1(now);
exit(0);
}
else{
int status;
waitpid(childpid,&status,0);
close(pipe1[1]);
dup2(pipe1[0],0);
solve(next);
close(pipe1[0]);
}
}
int main()
{
char buf[1024];
char *argv[1024];
parentpid = getpid();
signal(SIGINT, (sighandler_t)sigcat);
while(1)
{
memset(buf,0,sizeof(buf));
//printf("my pid is %d\n",getpid());
//printf("myshell #");
char c;
int len=0;
while(scanf("%c",&c)!=EOF)
{
if(c!='\n'&&c!='\0')buf[len++]=c;
else break;
}
fflush(stdin);
if(*buf=='\0')exit(1);
//printf("%s\n",buf);
char temp[1024];
strcpy(temp,buf);
int stdinput=dup(0);
int stdoutput=dup(1);
solve(buf);
dup2(stdinput,0);
dup2(stdoutput,1);
}
return EXIT_SUCCESS;
}
更多推荐
已为社区贡献1条内容
所有评论(0)