操作系统实验四:Shell的实现

您所在的位置:网站首页 linux实验报告shell编程 操作系统实验四:Shell的实现

操作系统实验四:Shell的实现

2024-06-05 18:59| 来源: 网络整理| 查看: 265

  一、实验内容

实现具有管道、重定向功能的shell

能够执行一些简单的基本命令,如进程执行、列目录等。

 

二、实验目的

1.学习并理解linux中shell的知识;

2.重点学会编程实现管道和重定向的功能;

3.实现自己的shell

 

三、设计思路和流程图 1.对输入的命令进行解析

实验内容主要是管道和重定向,这两个功能涉及shell“|”和“”等不同符号,所以要对输入的命令进行解析。初步按照空格来分,之后再按照、|这些涉及管道和重定向的符号来分。

2.简单命令的执行

使用函数execvp可以实现简单的命令,这些命令暂时不涉及管道和重定向,函数原型为int execvp(const char *file ,char * const argv []);,execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。为了不造成阻塞,这里启用了一个新线程实现它,最后父进程需等待子进程,以回收分配给它的资源。下面有些地方也用到这种方法。

3.输入输出重定向的实现

实现重定向的主要函数是freopen,FILE *freopen( const char *path, const char *mode, FILE *stream );path: 文件名,用于存储输入输出的自定义文件名。 mode: 文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。 stream: 一个文件,通常使用标准流文件。函数实现重定向,把预定义的标准流文件定向到由path指定的文件中。要注意的是第二个参数,刚开始我是用的a+,结果每次输出都加到文件末尾。后来查了一下,改成w+可以先清空再写入文件。

4.管道功能的实现

命令之间通过|符号来分隔,使用pipe函数来建立管道。如何分隔这些命令呢?上面是写一个函数通过空格来分离每个字符串,这里通过strtok_r函数来分隔命令。利用pipe函数生成的的读取端和写入端,第一条命令的输出作为第二条命令的输入,从而实现管道的功能。

 

四、主要数据结构及说明

主要使用了数组和指针,存放相关的命令,通过字符串操作实现一些基本的逻辑。

 

五、源程序并附上注释

上面所说的设计思路与程序中的函数是对应的。

#include #include #include #include #include #include #include #include #define hist_size 1024 char *hist[hist_size]; int f = 0; //to save change in directory int head = 0, filled = 0; //1-parse user's input void parse(char *word, char **argv) { int count = 0; memset(argv, 0, sizeof(char*)*(64));//copies 0 to the first 64 characters of the string pointed to by the argument argv. char *lefts = NULL; const char *split = " "; //setting delimeter while (1) { char *p = strtok_r(word, split, &lefts);//ref-"strtok-r":http://baike.baidu.com/view/6991509.htm?fr=aladdin if (p == NULL) { break; } argv[count] = p;//argv is an array, it stores each value of your input divided by " " word = lefts; //printf("%s\n",argv[count]); //printf("%s\n",word); count++; } if (strcmp(argv[0], "exit") == 0) exit(0); else if (strcmp(argv[0], "cd") == 0) { int ch = chdir(argv[1]); //ref-"chdir":http://baike.baidu.com/view/653970.htm?fr=aladdin /*if(ch0)//returns a pointer to first occurence after > or null { char *p = strtok_r(output, ">", &file); output += 1; //change2 file = trim(file);//get the first word of file, that is to say, get the first word after > flag = 1; //printf("file : %s output : %s \n",*argv,output); int old_stdout = dup(1); //printf("mark\n"); //output redirect FILE *fp1 = freopen(output, "w+", stdout);//ref-"freopen":http://baike.baidu.com/view/656692.htm?fr=aladdin //printf("mark\n"); execute_file(argv, file); fclose(stdout); FILE *fp2 = fdopen(old_stdout, "w");//ref-"fdopen":http://baike.baidu.com/view/656646.htm?fr=aladdin *stdout = *fp2; exit(0); } if (strstr(output, "", &file); file = trim(file); flag = 1; fflush(stdout); //printf("file : %s output : %s \n",file,output); fflush(stdout); int old_stdout = dup(1); FILE *fp1 = freopen(file, "w+", stdout); execute_input(argv, output); fclose(stdout); FILE *fp2 = fdopen(old_stdout, "w"); *stdout = *fp2; exit(0); } if (strstr(output, "|") > 0) { char *p = strtok_r(output, "|", &file); file = trim(file); flag = 1; char *args[64]; parse(file, args); int pfds[2]; pid_t pid, pid2; int status, status2; pipe(pfds); int fl = 0; if ((pid = fork()) < 0) { printf("error:fork failed\n"); exit(1); } if ((pid2 = fork()) < 0) { printf("error:fork failed\n"); exit(1); } if (pid == 0 && pid2 != 0) { close(1); dup(pfds[1]); close(pfds[0]); close(pfds[1]); fd = open(output, O_RDONLY); close(0); dup(fd); if (execvp(argv[0], argv) < 0) { close(pfds[0]); close(pfds[1]); printf("error:in exec"); fl = 1; exit(0); } close(fd); exit(0); } else if (pid2 == 0 && pid != 0 && fl != 1) { close(0); dup(pfds[0]); close(pfds[1]); close(pfds[0]); if (execvp(args[0], args) < 0) { close(pfds[0]); close(pfds[1]); printf("error:in exec"); exit(0); } } else { close(pfds[0]); close(pfds[1]); while (wait(&status) != pid); while (wait(&status2) != pid2); } exit(0); } fd = open(output, O_RDONLY); close(0); dup(fd); if (execvp(argv[0], argv) < 0) { printf("error:in exec"); } close(fd); exit(0); } else { while (wait(&status) != pid); } } //6-implement pipe void execute_pipe(char **argv, char *output) { int pfds[2], pf[2], flag; char *file; pid_t pid, pid2, pid3; int status, status2, old_stdout; pipe(pfds);//create pipe //pfds[0]:read pfds[1]:write int blah = 0; char *args[64]; char *argp[64]; int fl = 0; if ((pid = fork()) < 0) { printf("error:fork failed\n"); exit(1); } if ((pid2 = fork()) < 0) { printf("error:fork failed\n"); exit(1); } if (pid == 0 && pid2 != 0) { close(1); dup(pfds[1]); close(pfds[0]); close(pfds[1]); if (execvp(argv[0], argv) < 0)//run the command { close(pfds[0]); close(pfds[1]); printf("error:in exec"); fl = 1; kill(pid2, SIGUSR1); exit(0); } } else if (pid2 == 0 && pid != 0) { if (fl == 1){ exit(0); } if (strstr(output, "", &file); file = trim(file); flag = 1; //fflush(stdout);printf("file : %s output : %s \n",file,output);fflush(stdout); parse(output, args); blah = 1; } else { parse(output, args); } close(0); dup(pfds[0]); close(pfds[1]); close(pfds[0]); if (blah == 1) { old_stdout = dup(1); FILE *fp1 = freopen(file, "w+", stdout); } if (execvp(args[0], args) < 0) { fflush(stdout); printf("error:in exec %d", pid); kill(pid, SIGUSR1); close(pfds[0]); close(pfds[1]); } fflush(stdout); printf("HERE"); //kill (pid, SIGUSR1); if (blah == 1) { fclose(stdout); FILE *fp2 = fdopen(old_stdout, "w"); *stdout = *fp2; } } else { close(pfds[0]); close(pfds[1]); while (wait(&status) != pid); while (wait(&status2) != pid2); } } //7-implement pipe void execute_pipe2(char **argv, char **args, char **argp) { int status; int i; int pipes[4]; pipe(pipes); pipe(pipes + 2); if (fork() == 0) { dup2(pipes[1], 1); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); if (execvp(argv[0], argv) < 0) { fflush(stdout); printf("error:in exec"); fflush(stdout); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); exit(1); } } else { if (fork() == 0) { dup2(pipes[0], 0); dup2(pipes[3], 1); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); if (execvp(args[0], args) < 0) { fflush(stdout); printf("error:in exec"); fflush(stdout); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); exit(1); } } else { if (fork() == 0) { dup2(pipes[2], 0); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); if (execvp(argp[0], argp) < 0) { fflush(stdout); printf("error:in exec"); fflush(stdout); close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); exit(1); } } } } close(pipes[0]); close(pipes[1]); close(pipes[2]); close(pipes[3]); for (i = 0; i < 3; i++) wait(&status); } /* int main() { char word[1024]="ls>a.txt"; char *argv[1024]; char *file=NULL; char *p=strtok_r(word ,">", &file); file=trim(file); parse(word,argv); execute_file(argv,file); }*/ int main() { char line[1024]; char *argv[64]; char *args[64]; char *left; size_t size = 0; char ch; int count = 0; char *tri; char *second; char *file; int i; for (i = 0; i < hist_size; i++) { hist[i] = (char *)malloc(150); } while (1) { count = 0; int flag = 0; char *word = NULL; char *dire[] = { "pwd" }; fflush(stdout); printf("SHELL~"); fflush(stdout); execute(dire); //print the current directory, we can also use getcwd() printf("$"); int len = getline(&word, &size, stdin); if (*word == '\n') continue; word[len - 1] = '\0'; char *file = NULL; int i = 0; char *temp = (char *)malloc(150); strcpy(temp, word); parse(temp, argv); strcpy(hist[(head + 1) % hist_size], word); //storing an entry in history head = (head + 1) % hist_size; filled = filled + 1; for (i = 0; word[i] != '\0'; i++) { if (word[i] == '>') { //printf("%s\n",word); //has the initial command char *p = strtok_r(word, ">", &file); file = trim(file); //printf("%s\n",file); flag = 1; break; } else if (word[i] == '


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3