Linux之實現簡易的shell

1.打印提示符并獲取命令行

我們在使用shell的時候,發現我們在輸入命令是,前面會有:有用戶名版本當前路徑等信息,這里我們可以用環境變量去獲取:

  1 #include <stdio.h>2 #include <stdlib.h>3 4 const char* getUsername()5 {6     const char* name = getenv("USER");7     if(name) return name;8     else return "none";9 }10 11 const char* getHostname()12 {13     const char* hostname = getenv("HOSTNAME");14     if(hostname) return hostname;15     else return "none";16 }17 18 const char* getCwd()19 {20     const char* cwd = getenv("PWD");21     if(cwd) return cwd;22     else return "none";23 }24 25 int main()26 {27    printf("%s@%s %s\n",getUsername(),getHostname(),getCwd());                                                                                                                                                 28     return 0;29 }

寫。

看到我們打印出來的是絕對路徑, 而shell顯示的相對路徑, 但為了區分先這樣不去裁剪.?

 1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4                                                                                                            5 #define NUM 1024                                                                                           6                                                                                                            7 const char* getUsername()                                                                                  8 {                                                                                                          9     const char* name = getenv("USER");                                                                     10     if(name) return name;                                                                                  11     else return "none";                                                                                    12 }                                                                                                          13                                                                                                            14 const char* getHostname()                                                                                  15 {                                                                                                          16     const char* hostname = getenv("HOSTNAME");                                                             17     if(hostname) return hostname;                                                                          18     else return "none";                                                                                    19 }                                                                                                          20                                                                                                            21 const char* getCwd()                                                                                       22 {                                                                                                          23     const char* cwd = getenv("PWD");                                                                       24     if(cwd) return cwd;                                                                                    25     else return "none";                                                                                    26 }                                                                                                          27                                                                                                            28 int getUsercommand(char* command, int num)                                                                 29 {                                                                                                          30     printf("[%s@%s %s]",getUsername(),getHostname(),getCwd()); 31     char* r = fgets(command,num,stdin);//最終還是會輸入\n32     if(r == NULL) return 1;33                          34     command[strlen(command)-1] = '\0';//去除輸入的換行35     return 0;            36 }                        37                          38 int main()               39 {                        40     char usercommand[NUM];41     //1.打印提示符并且獲取命令字符串42     getUsercommand(usercommand,sizeof(usercommand));43     //2.                 44     //3.                                                                                                                                                                                                      45     printf("%s",usercommand);//回顯命令,用于測試46     return 0;47 }

?由于用scanf接收的遇到空格就會停止讀取, 所以用fgets, 而且用戶輸入完命令一定會輸入回車, 所以把最后一個回車符刪掉.


2.解析命令行

我們在輸入命令時, 可能不僅僅只是一段,比如說:"ls -a -l "。但是命令行解釋器內部在解析指令時應該傳遞的是"ls" "-a" "-l"這樣的多個個字符串, 所以我們還需要以空格來分割字符串。

    1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 5 #define DEBUG 16 #define NUM 10247 #define SIZE 648 #define SEP " "41 void commandSplit(char* in, char* out[])42 {43     int argc = 1;44     out[0] = strtok(in,SEP);
W> 45     while(out[argc++] = strtok(NULL,SEP));//報警不需要處理46 47 #ifdef DEBUG 48     for(int i = 0; out[i]; i++)49         printf("%d:%s\n",i,out[i]);50 #endif51 }52 53 int main()54 {55     char usercommand[NUM];56     char* argv[SIZE];57     //1.打印提示符并且獲取命令字符串58     getUsercommand(usercommand,sizeof(usercommand));59     //2.分割字符串60     commandSplit(usercommand, argv); 61     //3.                                                                                                                                                                                                    62     return 0;63 }            


3.執行對應的命令?

創建子進程和進程替換, 為了不影響shell, 我們將大部分指令的執行讓子進程去完成, 父進程只要阻塞等待子進程完成就好了。

    1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include <unistd.h>5 #include <sys/types.h>6 #include <sys/wait.h>7 8 //#define DEBUG 19 #define NUM 102410 #define SIZE 6411 #define SEP " "12 13 const char* getUsername()14 {15     const char* name = getenv("USER");16     if(name) return name;17     else return "none";18 }19 20 const char* getHostname()21 {22     const char* hostname = getenv("HOSTNAME");23     if(hostname) return hostname;24     else return "none";25 }26 27 const char* getCwd()28 {29     const char* cwd = getenv("PWD");30     if(cwd) return cwd;31     else return "none";32 }33 34 int getUsercommand(char* command, int num)                                                                                             35 {36     printf("[%s@%s %s]",getUsername(),getHostname(),getCwd()); 37     char* r = fgets(command,num,stdin);//最終還是會輸入\n38     if(r == NULL) return -1;39                                                                                                                                       40     command[strlen(command)-1] = '\0';//去除輸入的換行41     return strlen(command);42 }43 44 void commandSplit(char* in, char* out[])45 {46     int argc = 1;47     out[0] = strtok(in,SEP);
W> 48     while(out[argc++] = strtok(NULL,SEP));//報警不需要處理49 50 #ifdef DEBUG 51     for(int i = 0; out[i]; i++)52         printf("%d:%s\n",i,out[i]);53 #endif54 }55 56 int execute(char* argv[])57 {58     pid_t id = fork();59     if(id < 0) return 1;60     else if(id == 0)61     {62         //child63         //exec commond64         execvp(argv[0],argv);65         exit(1);66     }67 68     else69     {70         //father71         pid_t rid = waitpid(id,NULL,0);72         if(rid < 0)73             printf("wait fail\n");74     }75 76     return 0;77 }78 79 int main()80 {81     while(1)82     {83         char usercommand[NUM];84         char* argv[SIZE];85         //1.打印提示符并且獲取命令字符串86         int n = getUsercommand(usercommand,sizeof(usercommand));87         if(n <= 0) continue;//如果得到的是空串或者獲取失敗,不要往后執行88         //2.分割字符串89         commandSplit(usercommand, argv);90         //3.執行命令91         execute(argv);                                                                                                                 92     }93     return 0;94 }

?由于shell要一直運行, 所以要循環執行, 這里程序替換用execvp函數比較合適, 因為argv數組就是我們分割出的一個個命令的子串, argv[0]就是程序名, argv就是指令集. 父進程只進行wait即可.?

此外, getUsercommand函數可以優化一下, 返回的是輸入的指令的長度, 如果接收失敗(返回值為-1或者返回值是0只打印了空行)就不需要往下執行了, 直接continue進行下一輪.


4.特殊處理

?有一批命令, 不能讓子進程執行, 必須讓父進程自己執行, 這些命令叫內建命令.

1) cd指令

可以看到cd .. 之后并沒有發生什么異常, 但是pwd之后發現路徑沒有發生變化.?

我們為什么能在linux中進入某個目錄, 就是因為我們改變了shell的工作目錄. 每個進程都有自己的工作目錄, 我們想讓父進程的工作目錄發生改變, 但是程序替換之后都是子進程在執行cd .., 改變的都是子進程的工作目錄, 子進程改變完了又被回收了, 父進程完全沒發生變化, 所以cd應該實現成內建命令。

   79 void cd(const char* path)80 {81     chdir(path);82 }83 84 //1->yes,0->no85 int doBuildin(char* argv[])86 {87     if(strcmp(argv[0],"cd") == 0)88     {89         char* path = NULL;
W> 90         if(argv[1] == NULL) path = ".";91         else path = argv[1];92         cd(path);93         return 1;94     }95     else if(strcmp(argv[0],"ls")==0)96     {97         return 1;98     }99     return 0;                                                                                                                         100 }101 102 int main()103 {104     while(1)105     {106         char usercommand[NUM];107         char* argv[SIZE];108         //1.打印提示符并且獲取命令字符串109         int n = getUsercommand(usercommand,sizeof(usercommand));110         if(n <= 0) continue;//如果得到的是空串或者獲取失敗,不要往后執行111         //2.分割字符串112         commandSplit(usercommand, argv);113         //3.檢查是不是內建命令,是的話直接執行114         n = doBuildin(argv);115         if(n) continue;//是內建命令不用往后執行了116         //4.執行命令117         execute(argv);118     }119     return 0;120 }

所以在執行命令前先檢查是不是內建命令, 用返回值接收, 如果是就直接執行并返回1, continue不往下執行, 如果不是就返回0, 執行命令.?

?既然當前的工作目錄改變了, 那么環境變量PWD也要改變:?

chdir改變當前工作目錄, getcwd獲取當前的工作路徑, sprintf將tmp中的內容輸出到cwd中, putenv將cwd導入環境變量.?


2) export命令?

?

創建一個數組env儲存要導入的環境變量, 設置size指向導入到第幾個環境變量.

如果argv[1]是空就直接返回, 否則就導入環境變量, 注意不能直接把argv[1]導入進去, 因為argv[1]隨著指令的輸入時刻在變化, 需要開辟額外的空間去存儲.


3)echo指令


4)ls指令

我們執行的ls指令中不同的文件都有不同的顏色,所以對于ls我們可以在分割命令的時候加上一個“--color=auto”.


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/163897.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163897.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163897.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python如何快速查找到想要的文檔

字多不看版&#xff0c;直接體驗 待補充 演示代碼 # -*- coding:UTF-8 -*-# region 導入必要的依賴包 import os import subprocess from enum import Enum模塊名 pyperclip try:import pyperclip # 需要安裝 pyperclip 模塊&#xff0c;以支持粘貼板操作 except ImportEr…

PTA-成績轉換

本題要求編寫程序將一個百分制成績轉換為五分制成績。轉換規則&#xff1a; 大于等于90分為A&#xff1b;小于90且大于等于80為B&#xff1b;小于80且大于等于70為C&#xff1b;小于70且大于等于60為D&#xff1b;小于60為E。 輸入格式: 輸入在一行中給出一個整數的百分制成…

羊大師教你如何科學控制體重,輕松瘦下來

羊大師教你如何科學控制體重&#xff0c;輕松瘦下來 我們都知道&#xff0c;控制體重對于保持健康和美麗至關重要。然而&#xff0c;許多人在減肥的道路上走得波折重重&#xff0c;常常陷入挫敗和不知所措的境地。那么&#xff0c;如何科學控制體重&#xff0c;輕松瘦下來呢&a…

項目經理只需要有PMP證書就行?

就目前而言&#xff0c;大部分人對于項目經理的認識還停留在&#xff1a;有項目管理經驗&#xff0c;有對應的工作年限&#xff0c;有PMP證書。所以絕大多數人都認為只要報考了PMP項目管理&#xff0c;取得PMP證書&#xff0c;即可加入項目經理的圈子&#xff0c;薪資翻倍。 但…

協同過濾與矩陣分解講解(PPT)

總覽 協同過濾算法&#xff0c;就是一種完全依賴用戶和物品之間行為關系的推薦算法。 從字面理解&#xff0c;協同大家的反饋、評價和意見一起對海量的信息進行過濾&#xff0c;從中篩選出用戶可能感興趣的信息。 知識概括 從這幾個方面進行分析。 一、基于用戶的協同過濾 顯示…

6個PPT素材網站,讓你快速做出好看的PPT

找PPT模板一定要收藏好這6個網站&#xff0c;能讓你快速做出好看的PPT&#xff0c;重點十可以免費下載&#xff0c;趕緊收藏&#xff01; 1、菜鳥圖庫 https://www.sucai999.com/search/ppt/0_0_0_1.html?vNTYwNDUx 菜鳥圖庫網有非常豐富的免費素材&#xff0c;像設計類、辦公…

力扣labuladong——一刷day48

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、力扣1602. 找到二叉樹中最近的右側節點二、力扣437. 路徑總和 III三、力扣560. 和為 K 的子數組 前言 二叉樹的遞歸分為「遍歷」和「分解問題」兩種思維模式…

第7章-使用統計方法進行變量有效性測試-7.4.2-多元線性回歸

目錄 多元線性回歸模型 總體回歸函數 樣本回歸函數 線性回歸模型的假定 普通最小二乘法&#xff08;Ordinary Least Squares&#xff0c;OLS&#xff09; 擬合優度指標 F檢驗 回歸系數的t檢驗 Python中構建多元線性回歸模型 數據理解 數據讀取 數據清洗 相關分析 …

想考教師編制專業不對口怎么辦?

很多人在想要步入教師行業時&#xff0c;會遇到一個問題&#xff1a;專業不對口。這種情況可能會讓你感到困惑和沮喪&#xff0c;但不要氣餒&#xff0c;因為有很多方法可以讓你實現自己的夢想。 可以通過提高自己的教育水平和能力來彌補專業不對口的缺陷。你可以通過參加教師資…

品牌小紅書koc投放策略分享,純干貨!

作為中國具有影響力的時尚美妝社交平臺&#xff0c;小紅書與其充滿活力的用戶群體成為品牌尋找優質KOC合作的理想平臺。本文伯樂網絡傳媒將探討品牌如何利用小紅書的KOC投放策略&#xff0c;實現更廣泛的市場覆蓋和更有效的品牌營銷。 一、明確目標受眾與KOC合作需求 在開始策…

containerd Snapshots功能解析

containerd Snapshots功能解析 snapshot是containerd的一個核心功能&#xff0c;用于創建和管理容器的文件系統。 本篇containerd版本為v1.7.9。 本文以 ctr i pull命令為例&#xff0c;分析containerd的snapshot “創建” 相關的功能。 ctr命令 ctr image相關命令的實現在cmd…

《人件》讀書筆記

文章目錄 一、書名和作者二、書籍概覽2.1 主要論點和結構2.2 目標讀者和應用場景 三、核心觀點與主題3.1 管理團隊主題3.2 改善工作環境主題3.3 正確的人主題3.4 團隊項目管理主題 四、亮點與啟發4.1 最有影響的觀點4.2 對個人專業發展的啟示 五、批評與局限性5.1 可能存在爭議…

leetcode (力扣) 97. 交錯字符串(動態規劃)

文章目錄 題目描述思路分析完整代碼 題目描述 給定三個字符串 s1、s2、s3&#xff0c;請你幫忙驗證 s3 是否是由 s1 和 s2 交錯 組成的。 兩個字符串 s 和 t 交錯 的定義與過程如下&#xff0c;其中每個字符串都會被分割成若干 非空 子字符串&#xff1a; s s1 s2 … sn t …

數據庫——查詢連續的月份

一、GP或PGSQL with recursive t(n) as (select date(2023-01-01) union all select n1 from t where n < now()) select to_char(n, yyyy-mm) as ny from t group by ny order by ny 二、Hive select add_months(FROM_UNIXTIME(unix_timestamp(SUBSTR(start_date, 1, 7…

rdf-file:組件內置協議(SP、DE、FUND、FUND_INDEX)

Rdf-File根據協議布局模板和數據定義模板,來進行文件的解析與生成。通過協議布局和數據定義模板&#xff0c;能夠明確計算出頭尾占用的行數&#xff0c;這樣可以更精確的分離出head&#xff0c;body&#xff0c;tail。 目前組件實現的協議布局模板可以分為如下兩大類&#xff…

【深度學習實驗】圖像處理(一):Python Imaging Library(PIL)庫:圖像讀取、寫入、復制、粘貼、幾何變換、圖像增強、圖像濾波

文章目錄 一、實驗介紹二、實驗環境1. 配置虛擬環境2. 庫版本介紹 三、實驗內容0. 安裝 PIL 庫1. 圖像讀取和寫入a. 圖像讀取b. 圖像寫入c. 構建新圖像 2. 圖像復制粘貼a. 圖像復制b. 圖像局部復制c. 圖像粘貼 3. 幾何變換a. 圖像調整大小b. 圖像旋轉c. 圖像翻轉 4. 圖像增強a.…

cocos creator中AStar算法實例

引擎版本 —— cocos creator2.3.4

高端貓罐頭有哪些?精選的5款優質的貓罐頭推薦!

很多鏟屎官看貓貓吃貓糧吃膩了&#xff0c;或者貓貓平時不喜歡喝水&#xff0c;又或者看貓貓太瘦了就想入手幾款貓罐頭但是又愁于不會選擇&#xff0c;而且現在貓罐頭風這么大不知道選什么好~ 作為一個開寵物店7年的店長&#xff0c;對于貓咪的飲食健康我一直都很重視&#xff…

數據結構與算法編程題16

已知長度為n的線性表A&#xff0c;請寫一時間復雜度為O(n)、空間復雜度為O(1)的算法&#xff0c;該算法刪除線性表中所有值為item的數據元素。 item 3 數組下標 i 0 1 2 3 4 5 6 7 8 順序表&#xff1a; 1 2 3 4 3 3 5 3 7 #include <iostream> using namespace std;typ…

Linux常用基礎命令及重要目錄,配置文件功能介紹

目錄 一&#xff0c;Linux常用必備基礎命令 1&#xff0c;網絡類命令 2&#xff0c;文件目錄類命令 3&#xff0c;操作類命令 4&#xff0c;關機重啟命令 5&#xff0c;幫助命令 6&#xff0c;查看顯示類命令 7&#xff0c;命令常用快捷鍵 二&#xff0c;Linux重要目錄…