【Linux系統】進程替換 自主實現shell(簡易版)

1.先看代碼 && 現象

?我們用exec*函數執行新的程序,

exec*系列的函數,執行完畢后,后續的代碼不見了,因為被替換了。

execl的返回值可以不關心了,只要替換成功,就不會向后繼續運行,只要繼續運行了,一定是替換失敗了!

2.解釋原理

?進程 = 內核數據結構 + 代碼數據

進程的程序替換,有沒有創建新的進程?? 沒有的

站在被替換進程的角度:本質就是這個程序被加載到內存了!

怎么加載?exec*類似于Linux上的加載函數

3.將代碼改成多進程版

fork創建子進程,讓子進程自己去替換,wait等待

創建子進程,讓子進程完成任務:

  1. 讓子進程執行父進程代碼的一部分
  2. 讓子進程執行一個全新的程序

4.使用所有的替換方法,并且認識函數參數的含義

下面我們查的是這些替換方法,用man 3 execl

3手冊是c語言的標準庫GNU標準,所以我們實際查的是幾個內含系統調用的c語言函數。

?

?這是6個exec*系列函數。

?第一個execl函數:

path:我們要執行的程序,需要帶路徑(怎么找到程序你得告訴我)

exec后面的l -- list:就是要存放的選項列表,在命令行中怎么執行,你就怎么傳參!ls -a -l?

execl("/usr/bin/ls", "ls", "-a", "-l", NULL);

路徑代表你想執行誰,選項代表你想怎么執行!!!

帶l的是我們要傳入一個列表選項,那么帶v的呢?

?v:有動態數組的意思。

?明顯是要我們傳入一個數組,這個數組就包含我們想要的選項,

?帶p的exec函數:

用戶可以不傳要執行的文件的路徑(但是文件名要傳),直接告訴exec*,我要執行誰就行

p:查找這個程序,系統會自動在環境變量PATH中進行查找。

?

?e:environment環境變量。

envp[]:整體替換所有的環境變量!

  1. 用全新的給子進程。
  2. 用老的環境變量給子進程,environ。
  3. 老的環境變量稍微修改,給子進程。

上面的程序替換 ,我們替換的都是系統命令,可不可以替換我們自己寫的程序呢?

支持不同的應用場景!!!

當然可以。 而且可以替換用任何語言寫的無論是c++,java,python等語言都可進行替換,替換之后原程序pid不會改變,創建的子進程也不會改變,因為進程的替換,只是代碼和數據的替換,不影響原程序的pcb。

系統調用接口execve。

?上面的函數最終都將會走到系統調用接口。

5.寫一個自己的Shell(簡易版)

#include<stdio.h>    
#include<stdlib.h>    
#include<string.h>    
#include<ctype.h>    
#include<unistd.h>    
#include<errno.h>    
#include<sys/types.h>    
#include<sys/wait.h>    #define SIZE 512    
#define ZERO '\0'    
#define SEP " "    
#define NUM 32    
#define SkipPath(p) do{p += (strlen(p)-1);while(*p != '/')--p;}while(0)    char cwd[SIZE * 2];    
char* gArgv[NUM];    
int lastcode = 0;    void Die()    
{    exit(1);    
}    
const char* GetHome()    
{    const char* home = getenv("HOME");                                                                                                                                                   if(home == NULL) return "None";    return home;    
}    
const char* GetUserName()
{    const char* username = getenv("USER");if(username == NULL) return "None";return username;
}const char* GetHostName()
{const char* hostname = getenv("HOSTNAME");if(hostname == NULL) return "None";return hostname;
}const char* GetCwd()
{const char* cwd = getenv("PWD");if(cwd == NULL) return "None";return cwd;
}
//commandline:output
void MakeCommandLineAndPrint()
{char line[SIZE];const char* username = GetUserName();const char* hostname = GetHostName();const char* cwd = GetCwd();const char* GetCwd()
{const char* cwd = getenv("PWD");if(cwd == NULL) return "None";return cwd;                                                                                                                                                                          
}
//commandline:output
void MakeCommandLineAndPrint()
{char line[SIZE];const char* username = GetUserName();const char* hostname = GetHostName();const char* cwd = GetCwd();SkipPath(cwd);snprintf(line, sizeof(line), "[%s@%s %s]>", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1);printf("%s", line);fflush(stdout);
}
int GetUserCommand(char command[], size_t n)
{char* s = fgets(command, n, stdin);if(s == NULL) return -1;command[strlen(command) - 1] = ZERO;return strlen(command);
}
void SplitCommand(char command[], size_t n)
{(void)n;//"ls -a -l" ->  "ls", "-a", "-l"gArgv[0] = strtok(command, SEP);int index = 1;                                                                                                                                                                       while((gArgv[index] = strtok(NULL, SEP)))index++;// done, 故意寫成=,表示先賦值,在判斷,分割之后,strtok會返回NULL,剛好讓gArgv最后一個元素是NULL,并且while判斷結束
}void ExecuteCommand()
{pid_t id = fork();if(id < 0) Die();else if(id == 0){//childexecvp(gArgv[0], gArgv);exit(errno);}else {//fatherint status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){lastcode = WEXITSTATUS(status);if(lastcode != 0) printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode);}}
}
void Cd()
{const char* path = gArgv[1];if(path == NULL) path = GetHome();//path一定存在chdir(path);//刷新環境變量char temp[SIZE * 2];getcwd(temp, sizeof(temp));snprintf(cwd, sizeof(cwd), "PWD=%s", temp);putenv(cwd);//ok
}
int CheckBuildin()
{int yes = 0;const char* enter_cmd = gArgv[0];if(strcmp(enter_cmd, "cd") == 0){yes = 1;Cd();}else if(strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0){yes = 1;printf("%d\n", lastcode);lastcode = 0;}return yes;
}
int main()
{int quit = 0;while(!quit)                                                                                                                                                                         {//1.我們需要輸出一個命令行MakeCommandLineAndPrint();//2.獲取用戶命令行字符串char usercommand[SIZE];int n = GetUserCommand(usercommand, sizeof(usercommand));if(n <= 0) return 1;//3.命令行字符串分割SplitCommand(usercommand, sizeof(usercommand));//4.檢測命令是否是內鍵命令n = CheckBuildin();if(n) continue;//5,執行命令ExecuteCommand();}return 0;
}

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

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

相關文章

第5講:建立自己的C函數庫,js調用自己寫的C/C++函數,并包含依賴C/C++第三方靜態庫。

在javascript中&#xff0c;Array有很多內置的功能&#xff0c;比如Array.map&#xff0c;Array.filter&#xff0c;Array.find等等&#xff0c;能用內置的功能就用內置的功能&#xff0c;最好不要自己實現一套&#xff0c;因為底層調用的可能壓根就不是js語言本身&#xff0c;…

[AIGC] awk 和 sed

在Unix系統中&#xff0c;有兩種強大的用于文本操作的命令工具&#xff0c;它們就是awk和sed。這兩個命令工具是每個Linux用戶必備的知識之一&#xff0c;尤其對于需要進行文本處理或數據抽取的開發者來說&#xff0c;更加重要。 在實際開發過程中&#xff0c;我們常常需要處理…

JavaScript中的hasOwnProperty方法詳解

JavaScript中的hasOwnProperty方法詳解 大家好&#xff0c;我是免費搭建查券返利機器人省錢賺傭金就用微賺淘客系統3.0的小編&#xff0c;也是冬天不穿秋褲&#xff0c;天冷也要風度的程序猿&#xff01; 什么是hasOwnProperty方法&#xff1f; 在JavaScript中&#xff0c;h…

Wails 安裝初體驗

文章目錄 Wails 安裝說明1. 系統要求2. 安裝步驟3. 構建應用 結論 Wails 安裝說明 Wails 是一個用于構建桌面應用的 Go 框架&#xff0c;結合了現代前端技術。以下是安裝步驟&#xff1a; 1. 系統要求 Go 1.16 或更高版本Node.js 和 npm可選&#xff1a;適用于 Windows、mac…

【機器學習】機器學習的重要方法——強化學習:理論,方法與實踐

目錄 一、強化學習的核心概念 二、強化學習算法的分類與示例代碼 三.強化學習的優勢 四.強化學習的應用與挑戰 五、總結與展望 強化學習&#xff1a;理論&#xff0c;方法和實踐 在人工智能的廣闊領域中&#xff0c;強化學習&#xff08;Reinforcement Learning, RL&…

轉自羅翔老師的畢業寄語(二)

其實我很想祝大家一帆風順&#xff0c;可是我覺得這不現實。 智者說人這一生至少有三件事是無法避免的&#xff0c;一個是苦難&#xff0c;一個是邪惡&#xff0c;還有一個是人生的終點。所以真的愿我們每時每刻都在當下存儲足夠美好的記憶去對抗人生不期而至的苦楚&#xff0c…

基于源碼詳解ThreadPoolExecutor實現原理

個人博客地址 基于源碼詳解ThreadPoolExecutor實現原理 | iwts’s blog 內容拆分 這里算是一個總集&#xff0c;內容太多&#xff0c;拆分成幾個比較重要的小的模塊&#xff1a; ThreadPoolExecutor基于ctl變量的聲明周期管理 | iwts’s blog ThreadPoolExecutor 工作線程…

模板方法模式在金融業務中的應用及其框架實現

引言 模板方法模式&#xff08;Template Method Pattern&#xff09;是一種行為設計模式&#xff0c;它在一個方法中定義一個算法的框架&#xff0c;而將一些步驟的實現延遲到子類中。模板方法允許子類在不改變算法結構的情況下重新定義算法的某些步驟。在金融業務中&#xff…

可信和可解釋的大語言模型推理-RoG

大型語言模型&#xff08;LLM&#xff09;在復雜任務中表現出令人印象深刻的推理能力。然而&#xff0c;LLM在推理過程中缺乏最新的知識和經驗&#xff0c;這可能導致不正確的推理過程&#xff0c;降低他們的表現和可信度。知識圖譜(Knowledge graphs, KGs)以結構化的形式存儲了…

基于lightgbm hyperopt的旋轉機械故障診斷(Python)

前置文章&#xff1a; 將一維機械振動信號構造為訓練集和測試集&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/DTKjBo6_WAQ7bUPZEdB1TA 旋轉機械振動信號特征提取&#xff08;Python&#xff09; https://mp.weixin.qq.com/s/VwvzTzE-pacxqb9rs8hEVw import…

Python變量的命名規則與賦值方式

第二章&#xff1a;Python 基礎語法 第一節&#xff1a;變量的命名規則與賦值方式 2.1.1 引言 在編程中&#xff0c;變量是存儲數據的基本單元。變量的命名和賦值是編程語言中表達和操作數據的基礎。了解和遵循變量命名規則對于編寫清晰、可維護的代碼至關重要。 2.1.2 變量…

【linux】網絡基礎(1)

文章目錄 網絡基本概念網絡的定義網絡的類型局域網&#xff08;LAN&#xff09;廣域網&#xff08;WAN&#xff09; 網絡協議OSI七層模型TCP/IP模型TCP/IP模型的結構 網絡傳輸的基本流程計算機與計算機之間的通信計算機的信息處理封裝報頭 網絡基本概念 網絡的定義 1.網絡是指…

專題一: Spring生態初探

咱們先從整體脈絡上看下Spring有哪些模塊&#xff0c;重要的概念有個直觀印象。 從Spring框架的整體架構和組成對整體框架有個認知。 Spring框架基礎概念 Spring基礎 - Spring和Spring框架組成 上圖是從官網4.2.x獲取的原圖&#xff0c;目前我們使用最廣法的版本應該都是5.x&am…

GitHub每日最火火火項目(6.30)

項目名稱&#xff1a;modelscope / DiffSynth - Studio 項目介紹&#xff1a;該項目致力于讓用戶體驗擴散模型的神奇魅力。擴散模型是一種具有廣泛應用前景的技術&#xff0c;在圖像生成、音頻處理等領域展現出了強大的能力。通過DiffSynth - Studio&#xff0c;用戶可以深入探…

Arrays.asList 和 java.util.ArrayList 區別

理解 Java 中的 Arrays.asList 和 java.util.ArrayList 的區別 在 Java 編程中&#xff0c;Arrays.asList 方法和 java.util.ArrayList 是兩種常用的處理列表數據的方式。雖然它們在功能上看起來相似&#xff0c;但在內部實現和使用上有著本質的不同。本文將探討這兩種方式的區…

一區算法MPA|海洋捕食者算法原理及其代碼實現(Matlab/Python))

Matlab/Python&#xff1a; 本文KAU將介紹一個2020年發表在1區期刊ESWA上的優化算法——海洋捕食者算法 (Marine Predators Algorithm&#xff0c;MPA)[1] 該算法由Faramarzi等于2020年提出&#xff0c;其靈感來源于海洋捕食者之間不同的覓食策略、最佳相遇概率策略、海洋記…

【Linux】IO多路復用——select,poll,epoll的概念和使用,三種模型的特點和優缺點,epoll的工作模式

文章目錄 Linux多路復用1. select1.1 select的概念1.2 select的函數使用1.3 select的優缺點 2. poll2.1 poll的概念2.2 poll的函數使用2.3 poll的優缺點 3. epoll3.1 epoll的概念3.2 epoll的函數使用3.3 epoll的優點3.4 epoll工作模式 Linux多路復用 IO多路復用是一種操作系統的…

MCU復位時GPIO是什么狀態?

大家一定遇到過上電或者復位時外部的MOS電路或者芯片使能信號意外開啟&#xff0c;至此有經驗的工程師就會經常關心一個問題&#xff0c;MCU復位時GPIO是什么狀態&#xff1f;什么電路需要外部加上下拉&#xff1f; MCU從上電到啟動&#xff0c;實際可分為復位前和復位后、初始…

【WPF】Windows系統桌面應用程序編程開發新手入門-打造自己的小工具

電腦Windows系統上的桌面程序通常是用Visual Studio 開發工具編寫出來的&#xff0c;有兩種開發方式供選擇&#xff0c;一種是WindowForm&#xff0c;簡稱WinForm&#xff0c;另一種是Windows Presentation Foundation&#xff0c;簡稱WPF&#xff0c;這里將學習WPF項目。 文章…

大物3錯題整理

平衡位置&#xff1a;在O點上的位置 相位&#xff1a; 當N很大的時候&#xff0c;wxwywz。因此&#xff0c;平均平動動能除以3&#xff0c;就是能量均分定理。 W F在x上的積分 Π時無單位 180&#xff0c;就是單位 1rad&#xff0c;rad就是單位 左手定則、右手定則、安培定…