简单shell,支持重定向,多重管道。
i know this is very ugly, but just for fun.
#include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <ctype.h> #include <stdio.h> #define END_CMD 11 #define END_ARG 11 #define MAX_CMD_NUM (END_CMD-1) #define MAX_ARG_NUM (END_ARG-1) /* 思路 * (1)命令解析 * 扫描输入字符串,直接修改输入字符串为 execvp 的arg格式。 * (2)重定向 * 在扫描输入字符串时做好记录,后用dup2 标准输入输出实现 * (3)管道 * 扫描时做好记录,使用管道重定向实现。 * (4)多重管道 * 递归 * * 分层实现即可。 */ /* 细节 * scanf: 会被空格阻断 fgets不会 * * 管道重定向的实现:使用管道前一定要把没用的管道的关了。 * */ typedef unsigned char bool; #define true 1 #define false 0 void exec_pipe_cmd(char *(*cmd_vector)[MAX_ARG_NUM], int (*pipefd)[2], bool *is_pipe, int i) { int pid; close(pipefd[i][1]); // notice dup2(pipefd[i][0], STDIN_FILENO); close(pipefd[i][0]); i++; if (is_pipe[i] != true) { printf("return\n"); execvp(cmd_vector[i][0], cmd_vector[i]); } pipe(pipefd[i]); pid = fork(); if (pid < 0) { printf("fork2 err\n"); } else if (pid == 0){ close(pipefd[i][0]); // notice dup2(pipefd[i][1], STDOUT_FILENO); close(pipefd[i][1]); execvp(cmd_vector[i][0], cmd_vector[i]); } else { exec_pipe_cmd(cmd_vector, pipefd, is_pipe, i); } } void exec_cmd(char *(*cmd_vector)[MAX_ARG_NUM], int (*pipefd)[2], bool *is_pipe, int i) { int pid; if (is_pipe[i] != true) { printf("not pipe\n"); execvp(cmd_vector[i][0], cmd_vector[i]); } else { if (pipe(pipefd[i]) < 0) { perror("pipe \n"); } pid = fork(); if (pid < 0) { printf("fork2 err\n"); } else if (pid == 0){ close(pipefd[i][0]); // notice dup2(pipefd[i][1], STDOUT_FILENO); close(pipefd[i][1]); execvp(cmd_vector[i][0], cmd_vector[i]); } else { exec_pipe_cmd(cmd_vector, pipefd, is_pipe, i); } } } int main() { bool is_re_input = false; bool is_re_output = false; bool is_pipe[MAX_CMD_NUM]; char cmd[100] = {0}; char *cmd_vector[MAX_CMD_NUM][MAX_ARG_NUM]; char *ifile = NULL, *ofile = NULL; int ifd = -1, ofd= -1; int i = 0, cmd_index, arg_index; int pipefd[MAX_CMD_NUM][2]; while(1) { printf("hello@:"); fgets(cmd, sizeof(cmd), stdin); cmd_index = arg_index = i = 0; is_re_input = is_re_output = false; ifile = ofile = NULL; ifd = -1, ofd= -1; memset(is_pipe, false, sizeof(is_pipe)); while (cmd[i]) { if (isspace(cmd[i])) { i++; continue; } else if (cmd[i] == '-') { if (arg_index >= 10 || arg_index == 0) { printf("arg err input\n"); goto __again; } cmd_vector[cmd_index][arg_index] = cmd+i; arg_index++; while (cmd[i]) { if (isspace(cmd[i]) || cmd[i] == '\n') { cmd[i] = 0; i++; break; } else i++; } } else if (isalpha(cmd[i])) { cmd_vector[cmd_index][arg_index] = cmd+i; arg_index++; while (cmd[i]) { if (isspace(cmd[i]) || (cmd[i] == '\n')) { cmd[i] = 0; i++; break; } else { i++; } } } else if (cmd[i] == '>') { while (cmd[i]) { if (isalpha(cmd[i]) || isdigit(cmd[i]) || (cmd[i] == '_')) { ofile = cmd+i; break; } else { i++; } } if (!ofile) { printf("failed to redirect onput\n"); break; } while (cmd[i]) { if (isspace(cmd[i]) || (cmd[i] == '\n')) { cmd[i] = 0; i++; break; } else { i++; } } } else if (cmd[i] == '<') { while (cmd[i]) { if (isalpha(cmd[i]) || isdigit(cmd[i]) || (cmd[i] == '_')) { ifile = cmd+i; break; } else { i++; } } if (!ifile) { printf("failed to redirect input\n"); break; } while (cmd[i]) { if (isspace(cmd[i]) || (cmd[i] == '\n')) { cmd[i] = 0; i++; break; } else { i++; } } } else if (cmd[i] == '|') { if (cmd_index < MAX_CMD_NUM) { is_pipe[cmd_index] = true; cmd_vector[cmd_index][arg_index] = NULL; cmd_index++; arg_index = 0; } i++; } } __exec: cmd_vector[cmd_index][arg_index] = NULL; cmd_vector[cmd_index+1][0] = NULL; for (i = 0; cmd_vector[i][0]; i++) { if (fork() == 0) { if (ofile) { ofd = open(ofile, O_WRONLY | O_CREAT, 0644); if (ofd < 0) { perror("open ofile"); goto __exec; } if (dup2(ofd, STDOUT_FILENO) < 0) { perror("stdout dup2 err"); } } else if (ifile) { ifd = open(ifile, O_RDONLY); if (ifd < 0) { perror("open ifile"); goto __exec; } if (dup2(ifd, STDIN_FILENO) < 0) { perror("stdin dup2 err"); } } exec_cmd(cmd_vector, pipefd, is_pipe, i); } else { wait(NULL); while (is_pipe[i]) i++; } } __again: ; } }