分享一下去年修作業系統的時候寫出來的shell(最終成績97,因為做不到多重檔案重定向被扣了三分),shell主要結構大概是這樣,沒記錯的話,這也是恐龍書裡面的架構,接下來要做的事情僅僅只是依據此架構進行延伸。
while (TRUE){ type_prompt (); read_command (command, parameters); if (fork() != 0 ) { waitpid (-1 , &status, 0 ); } else { execvp (command, parameters); } }
將程式碼初步補充完之後,可以得到下面的架構,這部分是初步的完成品,也是我覺得很好的學習範例。
目前能夠執行基礎的指令,但不能實現pipe檢測和檔案重定向等功能。
#include <iostream> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <string.h> #include <vector> #define TRUE 1 using namespace std;void type_prompt () ;void read_command (char *, char **) ;const int MAX_LENGTH = 256 ;string local = "~\\" ; int main () { char *command = new char [MAX_LENGTH]; char **parameters = new char *[MAX_LENGTH]; int status = 0 ; cout << "Welcome to AfanShell" << endl; cout << "ctrl-c or ctrl-\\ to quit" << endl; while (TRUE) { type_prompt (); read_command (command, parameters); if (fork() != 0 ) { waitpid (-1 , &status, 0 ); } else { execvp (command, parameters); } } return 0 ; } void type_prompt () { cout << "AfanShell@" << "> " ; } void read_command (char *command, char **parameters) { char *tmp = new char [MAX_LENGTH]; char *token; int count = 0 ; int i = 0 ; for (i = 0 ; i < MAX_LENGTH; i++) { parameters[i] = NULL ; } cin.getline (tmp, MAX_LENGTH - 1 ); token = strtok (tmp, " " ); while (token != NULL ) { parameters[count] = new char [MAX_LENGTH]; strcpy (parameters[count], token); token = strtok (NULL , " " ); count++; if (count == MAX_LENGTH - 1 ) { break ; } } if (count == 0 ) { parameters[0 ] = new char [MAX_LENGTH]; strcpy (parameters[0 ], "echo" ); parameters[1 ] = new char [MAX_LENGTH]; strcpy (parameters[1 ], "No input received" ); } strcpy (command, parameters[0 ]); }
最終成果如下,將pipe補上,但要注意的是不可以做多重檔案重定向。
另外將程式碼改成c,雖然改動範圍不大就是了,希望對大家有幫助。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> static char *args[512 ];pid_t pid;int command_pipe[2 ];#define READ 0 #define WRITE 1 int execute (char *cmd, int input, int first, int last) ;void WaitChild (int n) ;char line[500 ];int n = 0 ;void type_prompt () ;int read_command (int input, int first, int last) ;int main () { printf ("Hello!\nThis is Afan@Shell\nctrl-c or ctrl-\\ to quit\n" ); while (true ) { type_prompt(); if (!fgets(line, 1024 , stdin )) return 0 ; int input = 0 ; int first = 1 ; char *cmd = line; char *next = strchr (cmd, '|' ); const char *file = "<>" ; if (strpbrk (cmd, file) != NULL ) { system(cmd); continue ; } while (next != NULL ) { *next = '\0' ; input = execute(cmd, input, first, 0 ); cmd = next + 1 ; next = strchr (cmd, '|' ); first = 0 ; } input = execute(cmd, input, first, 1 ); WaitChild(n); n = 0 ; } return 0 ; } void type_prompt () { printf ("Afan@Shell:$ " ); fflush(NULL ); } int read_command (int input, int first, int last) { int pipettes[2 ]; pipe(pipettes); pid = fork(); if (pid == 0 ) { if (first == 1 && last == 0 && input == 0 ) { dup2(pipettes[WRITE], STDOUT_FILENO); } else if (first == 0 && last == 0 && input != 0 ) { dup2(input, STDIN_FILENO); dup2(pipettes[WRITE], STDOUT_FILENO); } else { dup2(input, STDIN_FILENO); } if (execvp(args[0 ], args) == -1 ){ printf ("OOOOOOOh!It's wrong.\n" ); _exit(EXIT_FAILURE); } } if (input != 0 ) close(input); close(pipettes[WRITE]); if (last == 1 ) close(pipettes[READ]); return pipettes[READ]; } void WaitChild (int n) { int i; for (i = 0 ; i < n; i++) wait(NULL ); } char * SkipWhite (char *s) { while (isspace (*s)) s++; return s; } void Split (char *cmd) { cmd = SkipWhite(cmd); char *next = strchr (cmd, ' ' ); int i = 0 ; while (next != NULL ) { next[0 ] = '\0' ; args[i] = cmd; i++; cmd = SkipWhite(next + 1 ); next = strchr (cmd, ' ' ); } if (cmd[0 ] != '\0' ) { args[i] = cmd; next = strchr (cmd, '\n' ); next[0 ] = '\0' ; i++; } args[i] = NULL ; } int execute (char *cmd, int input, int first, int last) { Split(cmd); if (args[0 ] != NULL ) { n += 1 ; return read_command(input, first, last); } return 0 ; }