linux(1)- 简单的 shell 解释器
??????真正了不起的程序員對自己程序的每一個字節(jié)都了如指掌。
??????計算機科學領域中,沒有什么問題是增加一個中間層解決不了的。
目錄
- 做一個簡單的 Shell 解釋器
- 環(huán)境
- 思路
- 具體實現(xiàn)目標
- 方法
- 完整代碼
- 功能
- 運行截圖
做一個簡單的 Shell 解釋器
環(huán)境
??????Ubuntu20.04 64位虛擬機
思路
??????如何做一個類似的 shell 解釋器,按照不用重復造輪子的思想,所以最直接的思路是:編寫接口利用現(xiàn)成的 bash 。這是主要的思想。
具體實現(xiàn)目標
??????1,需要做一個交互界面,能夠仿照正常的終端格式打印出提示符
??????2,需要處理用戶的輸入指令,能夠?qū)τ脩舻拿钸M行處理
方法
??????1,包含于頭文件<pwd.h>下,在此需要用到的函數(shù)有三個,分別是 getpwuid() 獲取當前用戶名、gethostname() 獲取主機名和getcwd() 獲取當前路徑。如下:
??????2,每當有用戶進行輸入時,采用 fork()創(chuàng)建一個子進程,讓子進程來執(zhí)行具體的用戶輸入,執(zhí)行完畢用 wait() 來回收子進程。
??????執(zhí)行用戶輸入時,在此采用 exec 函數(shù)族中的 execvp(), 這個函數(shù)原型如下:
??????int execvp(const char *file, char *const argv[]);
??????關于返回值:該函數(shù)執(zhí)行失敗則直接返回-1。
??????第一個參數(shù)是要運行的腳本文件,會在環(huán)境變量PATH中查找并執(zhí)行,也就是說它可以直接對用戶輸入進行處理(比如 ls 命令),不需要進一步地轉(zhuǎn)化(將 ls 轉(zhuǎn)化為 /bin/ls ),用起來較為方便。
??????第二個參數(shù)是一個字符串數(shù)組,它是一個參數(shù)列表,下標為0,1,2…。注意:其中下標為0的參數(shù)是待執(zhí)行的命令本身,也就是腳本文件名。
??????還需要注意字符串數(shù)組最后一個參數(shù)必須為 NULL。
??????舉例如下:
??????當用戶輸入命令 ls -l 時,我們所需要做的工作是:假設字符串數(shù)組名為 argv,令 argv[0]=“l(fā)s” ,令 argv[1]="-l" ,令 argv[2]=NULL 。然后采用函數(shù)調(diào)用方法為 execvp(argv[0],argv) 來執(zhí)行 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];//參數(shù)列表 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);//將輸入字符串轉(zhuǎn)換為arg參數(shù)數(shù)組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)//執(zhí)行用戶命令(如ls命令:不帶p的需要采用/bin/ls形式,帶p的會自動查找環(huán)境變量。){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]);//每次都要釋放內(nèi)存。}}free(input);return 0;} void getInput(char* arg[10], char* input) {for (int i = 0; i < 10; i++)arg[i] = NULL; //保證最后一個參數(shù)始終為NULLif (input[0] == '\n')return;int i = 0,flag = 1;//i 作為input的下標掃描輸入字符. flag 用于多個空格符的檢測以及是否使用 malloc()int j,k = -1;//k 作為參數(shù)的下標,最大為9. j為每個參數(shù)中字符的下標,最大為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); //保證每個可用參數(shù)最后為'\0'j = 0;}arg[k][j++] = input[i];}i++;}return; }功能
??????能夠?qū)崿F(xiàn) ls,ps,touch,rm等命令,不能實現(xiàn) cd 命令,只能在當前目錄下進行操作。
??????輸入 exit 退出。
運行截圖
總結
以上是生活随笔為你收集整理的linux(1)- 简单的 shell 解释器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何在Ubuntu中安装java jdk
- 下一篇: linux(2)- 共享内存的实现