实现步骤:
- 接管用户输出命令字符串,拆分命令及参数存储。(自行设计数据存储构造)
- 实现一般命令加载性能
3.实现输出、输入重定向的性能
4.实现管道
5.反对多重管道
这道题感觉本人能力还没齐全看懂,看了大佬的代码https://blog.csdn.net/xiaoan0...
#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h>#include <sys/wait.h>#include <fcntl.h> #define MAXLINE 4096#define MAXPIPE 16#define MAXARG 8 struct { char *argv[MAXARG]; char *in, *out;} cmd[MAXPIPE+1]; int parse(char *buf, int cmdnum){ int n = 0; char *p = buf; cmd[cmdnum].in = cmd[cmdnum].out = NULL; //ls -l -d -a -F > out while (*p != '\0') { if (*p == ' ') { //将字符串中所有的空格,替换成'\0',不便后续拆分字符串 *p++ = '\0'; continue; } if (*p == '<') { *p = '\0'; while (*(++p) == ' '); /* cat < file 解决间断多个空格的状况*/ cmd[cmdnum].in = p; if (*p++ == '\0')//输出重定向<前面没有文件名 return -1; continue; } if (*p == '>') { *p = '\0'; while (*(++p) == ' '); cmd[cmdnum].out = p; if (*p++ == '\0') return -1; continue; } if (*p != ' ' && ((p == buf) || *(p-1) == '\0')) { if (n < MAXARG - 1) { cmd[cmdnum].argv[n++] = p++; //"ls -l -R > file" continue; } else { return -1; } } p++; } if (n == 0) { return -1; } cmd[cmdnum].argv[n] = NULL; return 0;} int main(void){ char buf[MAXLINE]; pid_t pid; int fd, i, j, pfd[MAXPIPE][2], pipe_num, cmd_num; char* curcmd, *nextcmd; while (1) { printf("mysh%% "); if (!fgets(buf, MAXLINE, stdin)) exit(0); // "ls -l\n" if (buf[strlen(buf)-1]=='\n') buf[strlen(buf)-1]='\0'; cmd_num = 0; nextcmd = buf; while ((curcmd = strsep(&nextcmd, "|"))) { if (parse(curcmd, cmd_num++)<0) { cmd_num--; break; } if (cmd_num == MAXPIPE + 1) break; } if (!cmd_num) continue; pipe_num = cmd_num - 1; //依据命令数确定要创立的管道数目 for (i = 0; i < pipe_num; i++) { //创立管道 if (pipe(pfd[i])) { perror("pipe"); exit(1); } } for (i = 0; i < cmd_num; i++) { //管道数目决定创立子过程个数 if ((pid = fork()) == 0) break; } if (pid == 0) { if (pipe_num) { //用户输出的命令中含有管道 if (i == 0) { //第一个创立的子过程 dup2(pfd[0][1], STDOUT_FILENO); close(pfd[0][0]); for (j = 1; j < pipe_num; j++) { //在该子过程执行期间,敞开该过程应用不到的其余管道的读端和写端 close(pfd[j][0]); close(pfd[j][1]); } } else if (i==pipe_num) { //最初一个创立的子过程 dup2(pfd[i-1][0], STDIN_FILENO); close(pfd[i-1][1]); for (j = 0; j < pipe_num-1; j++) { //在该子过程执行期间,敞开该过程不应用的其余管道的读/写端 close(pfd[j][0]); close(pfd[j][1]); } } else { dup2(pfd[i-1][0], STDIN_FILENO); //重定两头过程的规范输出至管道读端 close(pfd[i-1][1]); //close管道写端 dup2(pfd[i][1], STDOUT_FILENO); //重定两头过程的规范输入至管道写端 close(pfd[i][0]); //close管道读端 for (j = 0; j < pipe_num; j++) //敞开不应用的管道读写两端 if (j != i || j != i-1) { close(pfd[j][0]); close(pfd[j][1]); } } } if (cmd[i].in) { /*用户在命令中应用了输出重定向*/ fd = open(cmd[i].in, O_RDONLY); //关上用户指定的重定向文件,只读即可 if (fd != -1) dup2(fd, STDIN_FILENO); //将规范输出重定向给该文件 } if (cmd[i].out) { /*用户在命令中应用了输入重定向*/ fd = open(cmd[i].out, O_WRONLY|O_CREAT|O_TRUNC, 0644); //应用写权限关上用户指定的重定向文件 if (fd != -1) dup2(fd, STDOUT_FILENO); //将规范输入重定向给该文件 } execvp(cmd[i].argv[0], cmd[i].argv); //执行用户输出的命令 fprintf(stderr, "executing %s error.\n", cmd[i].argv[0]); exit(127); } /* parent */ for (i = 0; i < pipe_num; i++) { /*父过程不参加命令执行,敞开其把握的管道两端*/ close(pfd[i][0]); close(pfd[i][1]); } for (i = 0; i < cmd_num; i++) { /*循环回首子过程*/ wait(NULL); } }}
第一个函数parse()是用来解决输出格局的,如空格多输出了,重定向符号><与文件之间的书写标准等问题,前面的临时还在思考!