国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器

這篇具有很好參考價(jià)值的文章主要介紹了【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

本章的代碼可以訪問這里獲取。

由于程序代碼是一體的,本章在分開講解各部分的實(shí)現(xiàn)時(shí),代碼可能有些跳躍,建議在講解各部分實(shí)現(xiàn)后看一下源代碼方便理解程序。


一、觀察Shell的運(yùn)行狀態(tài)

我們想要制作一個(gè)簡(jiǎn)單的Shell解釋器,需要先觀察Shell是怎么運(yùn)行的,根據(jù)Shell的運(yùn)行狀態(tài)我們?cè)偃ミM(jìn)行模擬實(shí)現(xiàn)。

我們可以先考慮下面的指令與Shell的互動(dòng):

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器

我們仔細(xì)進(jìn)行分析可以發(fā)現(xiàn),Shell執(zhí)行上面的命令時(shí),可以被理解為下面的過程。

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器
當(dāng)然上面的命令都是普通命令,所以Shell都是通過創(chuàng)建子進(jìn)程的方式來執(zhí)行的,對(duì)于一些內(nèi)建命令(Shell自己去執(zhí)行命令)我們現(xiàn)在還不考慮,在后面的部分我們?cè)龠M(jìn)行進(jìn)一步的討論內(nèi)建命令應(yīng)該怎么去處理。

二、簡(jiǎn)單的Shell解釋器制作原理

通過觀察Shell的運(yùn)行狀態(tài),我們知道然后Shell讀取新的一行輸入,建立一個(gè)新的子進(jìn)程,在這個(gè)子進(jìn)程中運(yùn)行程序并等待這個(gè)進(jìn)程結(jié)束。

所以要寫一個(gè)shell,需要循環(huán)以下過程:

  1. 獲取命令行
  2. 解析命令行
  3. 建立一個(gè)子進(jìn)程(fork
  4. 替換子進(jìn)程(execvp),執(zhí)行替換后的程序
  5. 父進(jìn)程等待子進(jìn)程退出(wait

1、獲取命令行

我們?cè)谠?code>Shell中輸入的命令本質(zhì)上就是輸入一個(gè)字符串,因此我們想要獲取命令行,可以先創(chuàng)建一個(gè)字符數(shù)組commandstr,然后使用C語言的fgets函數(shù)從鍵盤中進(jìn)行讀取數(shù)據(jù)到字符數(shù)組里面,這樣我們就獲取了一個(gè)命令行了。

注意:

  1. 這里不能使用scanf函數(shù) ,這里的命令會(huì)包含空格會(huì)導(dǎo)致scanf讀取不到完整的數(shù)據(jù)。
  2. fgets函數(shù)會(huì)將我們輸入的命令時(shí)的最后一個(gè)的\n符也給讀取到字符數(shù)組內(nèi),我們需要特殊處理將\n進(jìn)行用\0進(jìn)行覆蓋
//這里包含的頭文件是我們整個(gè)程序需要用到的所有頭文件
#include<stdio.h>
#include<unistd.h>
#include<assert.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>

//這里的N用于定義字符數(shù)組的大小
#define N 128

int main()
{
  //存儲(chǔ)命令行的字符數(shù)組
  char commandstr[N] = "";
  
  //Shell要一直運(yùn)行接受命令,所以這里必須是死循環(huán)!
  while(1)
  {
  	//模擬Shell的提示符
    printf("[hong@machine MiniShell]# ");

    //從標(biāo)準(zhǔn)輸入流中讀取字符串
    char* s = fgets(commandstr, sizeof(commandstr), stdin);
    assert(s); //判斷fgets是否讀取成功


    //處理\n   示例字符串:ls -a -l\n\0
    commandstr[strlen(commandstr) - 1] = '\0';
   }
  

2、解析命令行

雖然我們通過前一步已經(jīng)拿到命令行,但是我們還不能直接使用,因?yàn)槲覀兡玫降淖址虚g可能有許多空格以及一些其他的問題,我們還需要將命令行的字符進(jìn)行切割提取出我們想要的子串,這樣才符合程序替換函數(shù)的要求。例如:將 ls -a -l提取成 ls ,-a , -l。

對(duì)于字符串的切割,我們可以使用C語言提供的strtok函數(shù),由于切割以后我們的字符串從一個(gè)變成了多個(gè),因此我們需要用一個(gè)字符串指針數(shù)組argv,存儲(chǔ)每一部分切割后的首地址,同時(shí)這個(gè)argv也可以直接傳遞給execvp函數(shù)進(jìn)行程序替換了。

//在全局域中 定義切割符
#define SEP " "

//main函數(shù)的外部 定義一個(gè)命令行切割函數(shù)
int split(char commandstr[], char* argv[])
{
  assert(commandstr);
  assert(argv);
  
  //第一次切割
  argv[0] = strtok(commandstr, SEP);
  if(argv[0] == NULL)
  {
  	//返回 -1表示異常退出
    return -1; 
  }

  //循環(huán)切割
  int i = 1;
  while((argv[i++] = strtok(NULL, SEP)));
  return 0;
}

//main函數(shù)內(nèi)部,while循環(huán)上面定義切割后的字符指針數(shù)組
char* argv[N] ={NULL};


//while循環(huán)內(nèi)部

	//切割字符串  例如將"ls -a -l " 變?yōu)?"ls" "-a" "-l"
    int n = split(commandstr, argv);
    if(n == -1)
    {
      //切割失敗就終止本次循環(huán)
      continue;
    }

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器

3、創(chuàng)建子進(jìn)程 進(jìn)行程序替換 父進(jìn)程等待

創(chuàng)建子進(jìn)程而我們可以使用fork函數(shù)進(jìn)行創(chuàng)建,創(chuàng)建完以后進(jìn)程的執(zhí)行流由一個(gè)變成了兩個(gè),我們?cè)谧舆M(jìn)程中進(jìn)行程序替換可以使用execvp命令,同時(shí)我們的argv[0]就是程序名,argv中存儲(chǔ)的就是命令按照什么方式進(jìn)行執(zhí)行。

最后我們的父進(jìn)程可以在外面進(jìn)行阻塞等待,然后獲取子進(jìn)程的退出碼和退出信息。

//main函數(shù)內(nèi)部,while循環(huán)上面定義退出碼變量
 int last_status = 0;
 
//while循環(huán)內(nèi)部

//創(chuàng)建子進(jìn)程,進(jìn)行命令處理
    pid_t id = fork();
    assert(id >= 0);

    if(id == 0)
    {
      //child process
      execvp(argv[0], argv);  
      //如果執(zhí)行到這里說明程序替換失敗  
      exit(-1);
    }
	
	//父進(jìn)程等待子進(jìn)程
    int status;
    int pid = waitpid(id, &status, 0); 
    //等待成功就提取退出碼信息
    if(pid >= 0)
    {
      last_status = WEXITSTATUS(status);
    }
  }
  return 0;

4、實(shí)際運(yùn)行

我們可以執(zhí)行 ls pwd ps -axj命令 看一看效果。
【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器

二、對(duì)簡(jiǎn)單的內(nèi)建命令進(jìn)行處理

我們知道內(nèi)建命令是讓Shell自己執(zhí)行的命令,而不是讓子進(jìn)程執(zhí)行的命令,例如cd命令就是內(nèi)建命令,因?yàn)槲覀円淖兊氖?code>Shell自己的工作目錄,而不是子進(jìn)程的工作目錄,類似的命令還有export env echo命令。

由于上面我們寫的程序執(zhí)行命令時(shí)都是交給子進(jìn)程去做的,所以我們上面寫的程序是沒有辦法執(zhí)行內(nèi)建命令的,或者說能執(zhí)行內(nèi)建命令,但不是我們想要的結(jié)果或目的。

所以接下來我們要對(duì)這個(gè)簡(jiǎn)單的Shell進(jìn)行改造,讓它能夠執(zhí)行一些簡(jiǎn)單的內(nèi)建命令,還有剛剛我們的ls命令沒有色彩,我們也要進(jìn)行一些修改。

1、給ls命令加上色彩

在真正的Shell中我們執(zhí)行的ls命令其實(shí)是ls --color=autols被我們真正的Shell進(jìn)行了起別名。

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器
我們?cè)谶\(yùn)行我們自己制作的Shell時(shí)也可以加上--color=auto。

//此段代碼應(yīng)該在切割字符串之后

//argv[0]就是我們的命令名
if(strcmp(argv[0], "ls") == 0)
    {
      int pos = 0;
      //尋找指針數(shù)組的結(jié)尾
      while(argv[pos++]);
      //在NULL位置加上 --color=auto
      argv[pos - 1] = "--color=auto";
      //將后一個(gè)位置置空
      argv[pos] = NULL;
    }

這樣以后我們?cè)谖覀冏约褐谱鞯?code>Shell中執(zhí)行ls命令時(shí)也會(huì)由顏色了!

2、支持cd命令

對(duì)于cd命令如果讓父進(jìn)程進(jìn)行執(zhí)行,我們可以調(diào)用系統(tǒng)調(diào)用chdir我們只需要傳遞一個(gè)參數(shù):路徑字符串,當(dāng)執(zhí)行成功時(shí)會(huì)返回0,執(zhí)行失敗會(huì)返回-1,并設(shè)置錯(cuò)誤碼。

【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器

//此段代碼應(yīng)該在ls添加顏色之后

else if(strcmp(argv[0], "cd") == 0)
    {
      //argv[1]里面存放的是路徑字符串
      if(argv[1] == NULL)
      {
        printf("沒有正確的路徑!\n");
        //設(shè)置錯(cuò)誤碼
        last_status = -1;
        continue;
      }
      	//執(zhí)行系統(tǒng)調(diào)用改變父進(jìn)程的工作目錄
        chdir(argv[1]);
        continue;
    }

3、支持export命令

export命令可以將一個(gè)本地變量加入到環(huán)境變量表中,我們讓我們自己制作的Shell完成expoprt命令可以用C語言提供的函數(shù)putenv函數(shù),但是在向環(huán)境變量表加入新的環(huán)境變量時(shí),我們要維護(hù)好我們加入到環(huán)境變量,這個(gè)環(huán)境變量不能夠被輕易的覆蓋,否則環(huán)境變量表在找我們的環(huán)境變量時(shí)就會(huì)找不到,所以我們還要?jiǎng)?chuàng)建一個(gè)我們自己維護(hù)的二維數(shù)組。

//在全局域中定義
// 自己維護(hù)的二維數(shù)組最多能向環(huán)境變量表幾個(gè)自定義的環(huán)境變量
#define MAX 64

//main函數(shù)內(nèi)部,while循環(huán)上面定義
//指向下一個(gè)要添加的環(huán)境變量的位置
 int env_index = 0;
//要維護(hù)的二維數(shù)組
 char envstr[MAX][N];

//此段代碼應(yīng)該在ls添加顏色之后
 else if(strcmp(argv[0], "export") == 0)
    {
    //聲明putenv函數(shù)否則會(huì)編譯器會(huì)有警告
      extern int putenv(char *string); 
      //argv[1]位置應(yīng)該是環(huán)境變量
      if(argv[1] == NULL)
      {
        printf("沒有輸入變量!\n");
        last_status = -1;
        continue;
      }
      //將argv[1]位置的環(huán)境變量,拷貝到env_str中,否則下一次解析的命令會(huì)覆蓋環(huán)境變量
      strcpy(envstr[env_index], argv[1]);
      //將環(huán)境變量導(dǎo)入環(huán)境變量表
      putenv(envstr[env_index++]);
    }

4、支持env命令

對(duì)于env命令我們只需要寫一個(gè)打印環(huán)境變量表的函數(shù)就能完成此命令了。

//main函數(shù)的外部 定義一個(gè)打印環(huán)境變量表的函數(shù)

void showEnv()
{
  extern char** environ;
  int i = 0;
  while(environ[i])
  {
    printf("%d : %s\n", i, environ[i++]);
  }
}

//此段代碼應(yīng)該在ls添加顏色之后
 else if(strcmp(argv[0], "env") == 0)
    {
      showEnv();
      continue;
    }

5、支持echo命令

echo命令可以用于打印環(huán)境變量,也可以打印退出碼,這取決于$后面是不是??我們就可以打印last_status,不是我們就用getenv命令拿到環(huán)境變量的內(nèi)容。文章來源地址http://www.zghlxwxcb.cn/news/detail-431273.html

//此段代碼應(yīng)該在ls添加顏色之后
else if(strcmp(argv[0], "echo") == 0)
    {
      if(*argv[1] == '$')
      {
        if(*(argv[1] + 1) == '?')
        {
          printf("process exit code %d\n", last_status);
          continue;
        }
        else
        {
          char* str = getenv(argv[1] + 1);
          printf("%s\n",str);
          continue;
        }
      }
    }

到了這里,關(guān)于【Linux】教你用進(jìn)程替換制作一個(gè)簡(jiǎn)單的Shell解釋器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Java Swing花樣玩法:教你用代碼制作六一兒童節(jié)的精美賀卡(簡(jiǎn)單版)

    Java Swing花樣玩法:教你用代碼制作六一兒童節(jié)的精美賀卡(簡(jiǎn)單版)

    ? 博主: 命運(yùn)之光 ? 專欄: Java經(jīng)典程序設(shè)計(jì) 前言:這篇博客在打開可能會(huì)自動(dòng)播放視頻,視頻有音樂,請(qǐng)及時(shí)靜音哈?? ? 目錄 ?前言 ?引言 ?簡(jiǎn)單介紹一下Javaswing這項(xiàng)技術(shù)簡(jiǎn)單介紹一下Javaswing這項(xiàng)技術(shù)(選讀,感興趣的可以了解一下哈(●\\\'?\\\'●)) ?程序展示 ?視頻

    2024年02月07日
    瀏覽(16)
  • 【Linux】進(jìn)程控制 — 進(jìn)程程序替換 + 實(shí)現(xiàn)簡(jiǎn)易shell

    【Linux】進(jìn)程控制 — 進(jìn)程程序替換 + 實(shí)現(xiàn)簡(jiǎn)易shell

    上一節(jié)我們講了進(jìn)程終止和進(jìn)程等待等一系列問題,并做了相應(yīng)的驗(yàn)證,本章將繼續(xù)對(duì)進(jìn)程控制進(jìn)行學(xué)習(xí),我們將學(xué)習(xí)進(jìn)程程序替換,進(jìn)行相關(guān)驗(yàn)證,運(yùn)用系統(tǒng)進(jìn)程程序替換接口,自己模擬寫一個(gè)shell,該shell能夠?qū)崿F(xiàn)執(zhí)行指令,等一系列命令行操作…… 概念引入: 將可執(zhí)行

    2024年02月06日
    瀏覽(15)
  • 【Linux】Linux進(jìn)程控制 --- 進(jìn)程創(chuàng)建、終止、等待、替換、shell派生子進(jìn)程的理解…

    【Linux】Linux進(jìn)程控制 --- 進(jìn)程創(chuàng)建、終止、等待、替換、shell派生子進(jìn)程的理解…

    柴犬: 你好啊,屏幕前的大帥哥or大美女,和我一起享受美好的今天叭?????? 1. 在調(diào)用fork函數(shù)之后, 當(dāng)執(zhí)行的程序代碼轉(zhuǎn)移到內(nèi)核中的fork代碼后 ,內(nèi)核需要分配 新的內(nèi)存塊 和 內(nèi)核數(shù)據(jù)結(jié)構(gòu) 給子進(jìn)程, 內(nèi)核數(shù)據(jù)結(jié)構(gòu)包括PCB、mm_struct和頁表,然后構(gòu)建起映射關(guān)系 ,同時(shí)

    2024年01月16日
    瀏覽(25)
  • 【linux】進(jìn)程替換的應(yīng)用|shell解釋器的實(shí)現(xiàn)

    【linux】進(jìn)程替換的應(yīng)用|shell解釋器的實(shí)現(xiàn)

    當(dāng)我們學(xué)過了進(jìn)程替換之后,本篇文章可以根據(jù)進(jìn)程替換的知識(shí)帶你自主實(shí)現(xiàn)一個(gè)shell命令行 實(shí)現(xiàn)步驟 1.顯示命令行提示 2.讀取輸入指令以及對(duì)應(yīng)選項(xiàng) 3.分割第二步的指令以及選項(xiàng)到命令行參數(shù)表中 4.處理內(nèi)建命令 5.進(jìn)程替換 我們通過觀察bash的命令行提示發(fā)現(xiàn)他是由三部分

    2024年04月26日
    瀏覽(95)
  • 【手把手教你制作一個(gè)簡(jiǎn)易版的shell】

    【手把手教你制作一個(gè)簡(jiǎn)易版的shell】

    為了簡(jiǎn)便,命令行中的提示符我們可以直接用printf打印,而具體執(zhí)行命令可以交給子進(jìn)程去做,現(xiàn)在的關(guān)鍵是如何將獲得的命令行中的命令切割。我們?cè)趯W(xué)習(xí)C語言時(shí)提到了strtok函數(shù),正好這個(gè)函數(shù)可以用來作為切割。 基本框架: 不知道大家注意到了沒有,我們從鍵盤中讀取

    2023年04月16日
    瀏覽(36)
  • 制作一個(gè)簡(jiǎn)單的Sifu人物替換Mod

    制作一個(gè)簡(jiǎn)單的Sifu人物替換Mod

    為什么做 突發(fā)奇想 某日看到了sifu mod相關(guān)的視頻,雖然人剛到靜心堂,但是還是想搞花活,于是就開始研究起來。一開始還算順利,但是后來有一個(gè)mod死活安裝不上去,游戲啟動(dòng)就是會(huì)報(bào)錯(cuò),應(yīng)該是游戲版本不兼容的問題,所以打算自己研究一下。 雖然過程看起來很簡(jiǎn)單,

    2023年04月11日
    瀏覽(18)
  • 教你用JavaScript制作輪播圖

    教你用JavaScript制作輪播圖

    歡迎來到我的小院,我是霍大俠,恭喜你今天又要進(jìn)步一點(diǎn)點(diǎn)了! 我們來用JavaScript編程實(shí)戰(zhàn)案例,做一個(gè)輪播圖。圖片每3秒自動(dòng)輪換,也可以點(diǎn)擊左右按鍵輪播圖片,當(dāng)圖片到達(dá)最左端或最右端時(shí),再點(diǎn)擊左右鍵圖片彈回最初始的圖片或最末尾的圖片。通過實(shí)戰(zhàn)我們將學(xué)會(huì)

    2024年02月11日
    瀏覽(21)
  • 教你用JavaScript制作鼠標(biāo)特效

    教你用JavaScript制作鼠標(biāo)特效

    歡迎來的我的小院,我是霍大俠,恭喜你今天又要進(jìn)步一點(diǎn)點(diǎn)了! 我們來用JavaScript編程實(shí)戰(zhàn)案例,做一個(gè)鼠標(biāo)愛心特效。鼠標(biāo)在頁面移動(dòng)時(shí)會(huì)出現(xiàn)彩色愛心特效。通過實(shí)戰(zhàn)我們將學(xué)會(huì)createElement方法、appendChild方法、setTimeout方法。 頁面出現(xiàn)后,鼠標(biāo)在頁面上移動(dòng)產(chǎn)生彩色愛心

    2024年02月11日
    瀏覽(27)
  • 教你如何使用Unity制作一個(gè)簡(jiǎn)單的跑酷游戲

    教你如何使用Unity制作一個(gè)簡(jiǎn)單的跑酷游戲

    其實(shí)用Unity制作游戲并不難,如果你想學(xué)習(xí),那我就建議你想從制作一個(gè)簡(jiǎn)單的跑酷游戲來找到興趣,因?yàn)槿绻阋婚_始就一直學(xué)習(xí)一些沒什么必要的語法,這樣就會(huì)讓你一開始就失去了信心,失去了學(xué)習(xí)Unity的動(dòng)力,所以如果你先學(xué)習(xí)如何制作一個(gè)簡(jiǎn)單的跑酷地圖,然后你就

    2024年02月04日
    瀏覽(26)
  • 【Unity】教你如何使用Unity制作一個(gè)簡(jiǎn)單的跑酷游戲

    【Unity】教你如何使用Unity制作一個(gè)簡(jiǎn)單的跑酷游戲

    其實(shí)用Unity制作游戲并不難,如果你想學(xué)習(xí),那我就建議你想從制作一個(gè)簡(jiǎn)單的跑酷游戲來找到興趣,因?yàn)槿绻阋婚_始就一直學(xué)習(xí)一些沒什么必要的語法,這樣就會(huì)讓你一開始就失去了信心,失去了學(xué)習(xí)Unity的動(dòng)力,所以如果你先學(xué)習(xí)如何制作一個(gè)簡(jiǎn)單的跑酷地圖,然后你就

    2024年02月21日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包