日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

C语言实现miniShell

發(fā)布時(shí)間:2024/4/11 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言实现miniShell 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Shell就是命令行的解釋器,因?yàn)樵贚inux下,是沒(méi)有圖形界面的,我們需要通過(guò)命令行輸入我們的命令,然后Shell將命令解析后反饋給Linux內(nèi)核,內(nèi)核運(yùn)算處理后再講結(jié)果通過(guò)Shell解析給用戶。

我們輸入的ls其實(shí)就是字符串,shell通過(guò)解析這個(gè)字符串,通過(guò)程序替換的方法將字符串ls替換為系統(tǒng)函數(shù)ls,完成操作,所以我們需要做的有一下幾步。

  • 獲取輸入的命令
  • 解析輸入的命令
  • 創(chuàng)建子進(jìn)程,通過(guò)子進(jìn)程進(jìn)行程序替換
  • 父進(jìn)程等待子進(jìn)程退出
  • 這里用到的知識(shí)都是前面幾篇Linux進(jìn)程概念和進(jìn)程控制中寫過(guò)的。

    我們還可以再這個(gè)基礎(chǔ)上,再添加例如重定向,管道,信號(hào)處理,后臺(tái)作業(yè),內(nèi)置命令等功能。但是因?yàn)檫@里是實(shí)現(xiàn)一個(gè)簡(jiǎn)易的shell,所以就只添加了重定向的功能。

    獲取輸入的命令

    頭文件

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/wait.h> #include<fcntl.h> #define MAX_CMD 1024 char buff[MAX_CMD]; //命令行的緩沖區(qū)大小1024個(gè)字節(jié)

    首先我們要從終端獲取數(shù)據(jù),同時(shí)需要對(duì)終端進(jìn)行模擬

    int get_cmd() {memset(buff, 0x00, MAX_CMD);printf("[lee@localhost ~]$ ");fflush(stdout);//模擬終端顯示fgets(buff, MAX_CMD - 1, stdin);//輸入buff[strlen(buff) - 1] = '\0';//最后一位是\0return 0; }

    解析輸入的命令

    我們需要將輸入的字符串中的所有命令都保存在字符串?dāng)?shù)組argv中,以NULL結(jié)尾

    char **do_parse(char *buff) {char *ptr = buff;int argc = 0;static char *argv[32];//將所有提取出來(lái)的命令保存進(jìn)argv中,因?yàn)樵诔绦蛘麄€(gè)生命域中都要使用, 聲明為靜態(tài)while('\0' != *ptr){if(' ' != *ptr){argv[argc++] = ptr;while('\0' != *ptr && ' ' != *ptr){ptr++;}*ptr = '\0';}ptr++;}//去掉空格,提取命令argv[argc] = NULL;//最后一位必須是NULLreturn argv; }

    輸出重定向

    這里實(shí)現(xiàn)的主要是輸出重定向中的>和>>

    > 重定向輸出符號(hào),覆蓋原來(lái)的內(nèi)容并寫入
    >>重定向輸出符號(hào),追加寫入

    void do_redirect(char *buff) {int redirect_flag = 0;//記錄>出現(xiàn)的次數(shù)char *redirect_file = NULL;char *ptr = buff;while(*ptr != '\0'){if(*ptr == '>'){*ptr++ = '\0';++redirect_flag;//如果這一位是>,則計(jì)數(shù)加一,并將這一位改寫為\0,防止被當(dāng)成命令解析if(*ptr == '>'){++redirect_flag;ptr++;}while(*ptr == ' ' && *ptr != '\0'){ptr++;}redirect_file = ptr;//檢測(cè)完>>之后,后面的就是重定向的文件名,將其解析出來(lái)while(*ptr != ' ' && *ptr != '\0'){ptr++;} *ptr = '\0';}ptr++;}if(redirect_flag == 1){int fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);dup2(fd, 1);//將標(biāo)準(zhǔn)輸出重定向到文件//如果只出現(xiàn)了一個(gè)>,則說(shuō)明是覆蓋重定向,以O(shè)_TRUNC覆蓋模式打開(kāi)}else if(redirect_flag == 2){int fd = open(redirect_file, O_WRONLY|O_CREAT|O_APPEND, 0664);dup2(fd, 1);//>出現(xiàn)了兩次,說(shuō)明是追加重定向,以O(shè)_APPEND追加模式打開(kāi)} }

    程序替換

    int do_exec(char *buff) {char **argv ={ NULL };int pid = fork();//創(chuàng)建子進(jìn)程, 在子進(jìn)程中進(jìn)行程序替換if(0 == pid){ do_redirect(buff);//重定向argv = do_parse(buff);//解析命令if(NULL != argv[0]){execvp(argv[0], argv);//替換進(jìn)程}else{exit(-1);//輸入命令錯(cuò)誤則退出進(jìn)程} } else{waitpid(pid, NULL, 0);//等待子進(jìn)程退出,防止僵尸進(jìn)程} return 0; }

    接下來(lái)調(diào)用就可以

    int main(int argc, char*argv[]) {while(1){//如果命令輸入正確則啟用程序替換。if(!get_cmd())do_exec(buff);}return 0; }

    為了能夠以后更好的管理和修改,寫一個(gè)makefile

    minishell:minishell.cgcc $^ -o $@

    下面來(lái)驗(yàn)證一下

    基本的命令都可以解析

    再試一下輸出重定向

    可以看到,兩種重定向都可以正常運(yùn)作。

    管道,信號(hào)處理,后臺(tái)作業(yè),內(nèi)置命令等功能的話可以再這個(gè)shell的基礎(chǔ)上再進(jìn)行修改,但這里只是實(shí)現(xiàn)一個(gè)簡(jiǎn)單的命令行解釋器,所以就先實(shí)現(xiàn)這些簡(jiǎn)易的功能。

    代碼非常簡(jiǎn)單,總共也就100多行
    完整代碼

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/wait.h> #include<fcntl.h> #define MAX_CMD 1024char buff[MAX_CMD];//1.獲取命令 int get_cmd() {memset(buff, 0x00, MAX_CMD);printf("[lee@localhost ~]$ ");fflush(stdout);//模擬終端顯示fgets(buff, MAX_CMD - 1, stdin);buff[strlen(buff) - 1] = '\0';return 0;}//2.解析命令 char **do_parse(char *buff) {char *ptr = buff;int argc = 0;static char *argv[32];while('\0' != *ptr){if(' ' != *ptr){argv[argc++] = ptr;while('\0' != *ptr && ' ' != *ptr){ptr++;}*ptr = '\0';}ptr++;}//去掉空格,提取命令argv[argc] = NULL;return argv; }void do_redirect(char *buff) {int redirect_flag = 0;char *redirect_file = NULL;char *ptr = buff;while(*ptr != '\0'){if(*ptr == '>'){*ptr++ = '\0';++redirect_flag;if(*ptr == '>'){++redirect_flag;ptr++;}while(*ptr == ' ' && *ptr != '\0'){ptr++;}redirect_file = ptr;while(*ptr != ' ' && *ptr != '\0'){ptr++;}*ptr = '\0';}ptr++;}if(redirect_flag == 1){int fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);dup2(fd, 1);}else if(redirect_flag == 2){int fd = open(redirect_file, O_WRONLY|O_CREAT|O_APPEND, 0664);dup2(fd, 1);} }//4.程序替換 int do_exec(char *buff) {char **argv ={ NULL };int pid = fork();//創(chuàng)建子進(jìn)程, 在子進(jìn)程中進(jìn)行程序替換if(0 == pid){ do_redirect(buff);argv = do_parse(buff);if(NULL != argv[0]){execvp(argv[0], argv);//替換進(jìn)程}else{exit(-1);//輸入命令錯(cuò)誤則退出進(jìn)程}} else{waitpid(pid, NULL, 0);//等待子進(jìn)程退出}return 0; }int main(int argc, char*argv[]) {while(1){if(!get_cmd())do_exec(buff);}return 0; }

    總結(jié)

    以上是生活随笔為你收集整理的C语言实现miniShell的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。