linux(1)- 简单的 shell 解释器
??????真正了不起的程序員對自己程序的每一個字節都了如指掌。
??????計算機科學領域中,沒有什么問題是增加一個中間層解決不了的。
目錄
- 做一個簡單的 Shell 解釋器
- 環境
- 思路
- 具體實現目標
- 方法
- 完整代碼
- 功能
- 運行截圖
做一個簡單的 Shell 解釋器
環境
??????Ubuntu20.04 64位虛擬機
思路
??????如何做一個類似的 shell 解釋器,按照不用重復造輪子的思想,所以最直接的思路是:編寫接口利用現成的 bash 。這是主要的思想。
具體實現目標
??????1,需要做一個交互界面,能夠仿照正常的終端格式打印出提示符
??????2,需要處理用戶的輸入指令,能夠對用戶的命令進行處理
方法
??????1,包含于頭文件<pwd.h>下,在此需要用到的函數有三個,分別是 getpwuid() 獲取當前用戶名、gethostname() 獲取主機名和getcwd() 獲取當前路徑。如下:
??????2,每當有用戶進行輸入時,采用 fork()創建一個子進程,讓子進程來執行具體的用戶輸入,執行完畢用 wait() 來回收子進程。
??????執行用戶輸入時,在此采用 exec 函數族中的 execvp(), 這個函數原型如下:
??????int execvp(const char *file, char *const argv[]);
??????關于返回值:該函數執行失敗則直接返回-1。
??????第一個參數是要運行的腳本文件,會在環境變量PATH中查找并執行,也就是說它可以直接對用戶輸入進行處理(比如 ls 命令),不需要進一步地轉化(將 ls 轉化為 /bin/ls ),用起來較為方便。
??????第二個參數是一個字符串數組,它是一個參數列表,下標為0,1,2…。注意:其中下標為0的參數是待執行的命令本身,也就是腳本文件名。
??????還需要注意字符串數組最后一個參數必須為 NULL。
??????舉例如下:
??????當用戶輸入命令 ls -l 時,我們所需要做的工作是:假設字符串數組名為 argv,令 argv[0]=“ls” ,令 argv[1]="-l" ,令 argv[2]=NULL 。然后采用函數調用方法為 execvp(argv[0],argv) 來執行 ls -l 命令。
完整代碼
#include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<string.h> #include<stdlib.h> #include<sys/wait.h> #include<pwd.h>#define SIZE 512 #define LEN 32 void getInput(char* arg[],char* input); int main() {printf("hello,It's me.\n");char* input=(char*)malloc(SIZE);//存儲用戶輸入的命令char* arg[10];//參數列表 1+9char exit_p[] = "exit"; //退出處理char exit_input[5];struct passwd* a = getpwuid(getuid());//獲得提示符char name[32];gethostname(name, 31);char current_dir[128];getcwd(current_dir, 127);while (1){printf("%s@%s:%s$ ",a->pw_name,name,current_dir);//打印提示符memset(input, 0, SIZE);//每次都清0fgets(input,SIZE-1,stdin);//獲得用戶輸入memcpy(exit_input, input, 4);//進行退出判斷,是否為"exit\n"if(input[4]=='\n'){exit_input[4]='\0';if (strcmp(exit_p, exit_input) == 0)break; //用戶輸入exit進行退出}getInput(arg, input);//將輸入字符串轉換為arg參數數組pid_t pid = fork();if (pid < 0)printf("error in fork().\n");else if (pid == 0){printf("my pid is %d,I will execute the task.\n\n", getpid());if (execvp(arg[0], arg) < 0)//執行用戶命令(如ls命令:不帶p的需要采用/bin/ls形式,帶p的會自動查找環境變量。){printf("error in execv().\n");exit(-1);}elseexit(0);}else{int status;int re = wait(&status);printf("\nchild process quit with status%d.\n", status);printf("child process pid=%d.\n", re);for (int i = 0; i < 10; i++)if (arg[i] != NULL)free(arg[i]);//每次都要釋放內存。}}free(input);return 0;} void getInput(char* arg[10], char* input) {for (int i = 0; i < 10; i++)arg[i] = NULL; //保證最后一個參數始終為NULLif (input[0] == '\n')return;int i = 0,flag = 1;//i 作為input的下標掃描輸入字符. flag 用于多個空格符的檢測以及是否使用 malloc()int j,k = -1;//k 作為參數的下標,最大為9. j為每個參數中字符的下標,最大為31while (input[i] != '\n'){if (input[i] == ' ')flag = 1;else{if(flag){flag = 0;k++;arg[k] = (char*)malloc(LEN);memset(arg[k], 0, LEN); //保證每個可用參數最后為'\0'j = 0;}arg[k][j++] = input[i];}i++;}return; }功能
??????能夠實現 ls,ps,touch,rm等命令,不能實現 cd 命令,只能在當前目錄下進行操作。
??????輸入 exit 退出。
運行截圖
總結
以上是生活随笔為你收集整理的linux(1)- 简单的 shell 解释器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Ubuntu中安装java jdk
- 下一篇: linux(2)- 共享内存的实现