乐趣区

关于linux内核模块:Linux实现简单的交互式shell

实现步骤:

  1. 接管用户输出命令字符串,拆分命令及参数存储。(自行设计数据存储构造)
  2. 实现一般命令加载性能

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()是用来解决输出格局的,如空格多输出了,重定向符号 >< 与文件之间的书写标准等问题,前面的临时还在思考!

退出移动版