操作系统实验四:Shell的实现
⼀、实验内容
H1
实现具有管道、重定向功能的shell
能够执⾏⼀些简单的基本命令,如进程执⾏、列⽬录等。
⼆、实验⽬的
H1
1.学习并理解linux中shell的知识;
2.重点学会编程实现管道和重定向的功能;
3.实现⾃⼰的shell
三、设计思路和流程图
H1
1.对输⼊的命令进⾏解析
H2
实验内容主要是管道和重定向,这两个功能涉及shell“|”和“<”以及“>”等不同符号,所以要对输⼊的命令进⾏解析。初步按照空格来分,之后再按照<、>、|这些涉及管道和重定向的符号来分。
2.简单命令的执⾏
H2
使⽤函数execvp可以实现简单的命令,这些命令暂时不涉及管道和重定向,函数原型为int execvp(const char *file ,char * const argv []);,execvp()会从PATH 环境变量所指的⽬录中查符合参数file 的⽂件名,到后便执⾏该⽂件,然后将第⼆个参数argv传给该欲执⾏的⽂件。为了不造成阻塞,这⾥启⽤了⼀个新线程实现它,最后⽗进程需等待⼦进程,以回收分配给它的资源。下⾯有些地⽅也⽤到这种⽅法。
3.输⼊输出重定向的实现
H2
实现重定向的主要函数是freopen,FILE *freopen( const char *path, const char *mode, FILE *stream );path: ⽂件名,⽤于存储输⼊输出的⾃定义⽂件名。 mode: ⽂件打开的模式。和fopen中的模式(如r-只读, w-写)相同。 stream: ⼀个⽂件,通常使⽤标准流⽂件。函数实现重定向,把预定义的标准流⽂件定向到由path指定的⽂件中。要注意的是第⼆个参数,刚开始我是⽤的a+,结果每次输出都加到⽂件末尾。后来查了⼀下,改成w+可以先清空再写⼊⽂件。
4.管道功能的实现
H2
命令之间通过|符号来分隔,使⽤pipe函数来建⽴管道。如何分隔这些命令呢?上⾯是写⼀个函数通过空格来分离每个字符串,这⾥通过strtok_r函数来分隔命令。利⽤pipe函数⽣成的的读取端和写⼊端,第⼀条命令的输出作为第⼆条命令的输⼊,从⽽实现管道的功能。
四、主要数据结构及说明
H1
主要使⽤了数组和指针,存放相关的命令,通过字符串操作实现⼀些基本的逻辑。
五、源程序并附上注释
H1
上⾯所说的设计思路与程序中的函数是对应的。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include<signal.h>
#include <fcntl.h>
#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":baike.baidu/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":baike.baidu/view/653970.htm?fr=aladdin
/*if(ch<0)
{
printf("No such file or directory %d\n.",ch);
}*/
f = 1;
}
}
//2-get the first word
char *trim(char *string)//remove extra spaces
{
int i = 0;
int j = 0;
char *ptr = malloc(sizeof(char*)*strlen(string));
for (i = 0; string[i] != '\0'; i++)
if (string[i] != ' ')
shell代码{
ptr[j] = string[i];
j++;
}
ptr[j] = '\0';
string = ptr;
//printf("%s\n",string);
//printf("%d\n",j);
return string;
}
//3-execute the basic order
void execute(char **argv)
{
pid_t pid;
int status;
//fork child process
if ((pid = fork()) < 0)
{
printf("error:fork failed.\n");
exit(1);
}
else if (pid == 0)
{
if (execvp(argv[0], argv) < 0 && strcmp(argv[0], "cd"))//ref-"execvp":baike.baidu/view/1745420.htm?fr=aladdin printf("error:invalid command.\n");
exit(0);
}
else
{
while (wait(&status) != pid)//ref-"wait":see.xidian.edu/cpp/html/289.html
;
}
}
//4-output redirect
//output:file in which we need to print the output
void execute_file(char **argv, char *output)
{
//printf("output:%s\n",output);
int status, flag;
char *file = NULL;
if ((pid = fork()) < 0)
{
printf("error:fork failed.\n");
exit(1);//fclose(fd1);
}
else if (pid == 0)
{
if (strstr(output, ">")>0)//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":baike.baidu/view/656692.htm?fr=aladdin //printf("mark\n");
execute_file(argv, file);
fclose(stdout);
FILE *fp2 = fdopen(old_stdout, "w");//ref-"fdopen":baike.baidu/view/656646.htm?fr=aladdin
*stdout = *fp2;
exit(0);
}
if (strstr(output, "<") > 0)
{
char *p = strtok_r(output, "<", &file);
file = trim(file);
flag = 1;
int fd = open(file, O_RDONLY);//ref-"open":see.xidian.edu/cpp/html/238.html
if (fd<0)
{
printf("No such file or directory.");
exit(0);
}
}
if (strstr(output, "|")>0)
{
fflush(stdout); printf("here"); fflush(stdout);
char *p = strtok_r(output, "|", &file);
file = trim(file);
flag = 1;
//fflush(stdout);printf("%s",file);fflush(stdout);
char *args[64];
parse(file, args);
execute(args);
}
int old_stdout = dup(1);
FILE *fp1 = freopen(output, "w+", stdout);
if (execvp(argv[0], argv) < 0)
printf("error:in exec");
fclose(stdout);
FILE *fp2 = fdopen(old_stdout, "w");
*stdout = *fp2;
exit(0);
}
else
{
while (wait(&status) != pid)
;
}
}
//5-input redirect
void execute_input(char **argv, char *output)
{
pid_t pid;
int fd;
char *file;
int flag = 0;
int status;
if ((pid = fork()) < 0)
{
}
else if (pid == 0)
{
if (strstr(output, "<")>0)
{
char *p = strtok_r(output, "<", &file);
file = trim(file);
flag = 1;
//printf("file : %s output : %s \n",file,output); fd = open(output, O_RDONLY);
if (fd<0)
{
printf("No such file or directory.");
exit(0);
}
output = file;
}
if (strstr(output, ">")>0)
{
char *p = strtok_r(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);
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论