进程间程序替换和minishell
生活随笔
收集整理的這篇文章主要介紹了
进程间程序替换和minishell
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
進程間程序替換和minishell
文章目錄
- 進程間程序替換和minishell
- 一、進程間程序替換的原理
- 二、exec函數族的用法及
- 三、它們之間的聯系
- 四、簡易的shell
一、進程間程序替換的原理
1.用fork創建子進程后執行的是和父進程相同的程序(但有可能執行不同的代碼分支),這樣就達不到創建進程的目的。
2.子進程往往要調用一種exec函數以執行另一個程序。當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序替換,從新程序的啟動例程開始執行。
3.調用exec并不創建新進程,只是把進程的數據和代碼替換一下,讓其執行別的邏輯,所以調用exec前后該進程的pid并未改變。
如圖所示,有一個進程創建出的子進程本來是拷貝父進程的PCB,如果不進行分流,那么父子進程將會執行一摸一樣的邏輯,所以現在用exec函數族把子進程的數據段和代碼段替換掉,讓其執行別的邏輯
二、exec函數族的用法及
1.execl函數:
int execl(const char *path, const char *arg, ...);| const char *path | 帶路徑的可執行程序(“/usr/bin/ls”) |
| const char *arg | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l) |
| … | 可變參數列表,必須以NULL結尾,作為終止符 |
2.execlp函數
int execlp(const char *file, const char *arg, ...);| const char *file | 可執行程序的名稱,但是注意該可執行程序必須在PATH環境變量中可以被找到,否者就會替換失敗 |
| const char *arg | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l) |
| … | 可變參數列表,必須以NULL結尾,作為終止符 |
總結一下exec函數族中代p和不帶p的區別:如果帶p,說明進程運行時會去環境變量中尋找,第一個參數直接傳遞可執行程序名即可。對于不帶p,第一個參數必須指明可執行程序的路徑。
3.execle函數
int execle(const char *path, const char *arg, ...,char *const envp[]);| const char *path | 帶路徑的可執行程序 |
| const char *arg | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數(ls -a -l) |
| … | 可變參數列表,必須以NULL結尾,作為終止符 |
| char *const envp[] | 程序員自己組建環境變量,如果沒有則認為當前進程沒有環境變量,注意??環境變量也是以NULL結尾的 |
4.execv函數
總結一下帶e和不帶e的區別:如果函數帶e表示需要自己組裝環境變量。不帶e則不需要自己組裝環境變量
| const char *path | 帶路徑的可執行程序 |
| const char *argv[] | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾 |
5.execvp函數
int execvp(const char *file, char *const argv[]);| const char *file | 可執行程序名,不帶路徑 |
| char *const argv[] | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾 |
6.execve函數
int execve(const char *path, char *const argv[], char *const envp[]);| const char *path | 帶路徑的可執行程序名 |
| char *const argv[] | 給可執行程序傳遞的參數,但必須是以可執行程序名作為第一個參數,以NULL結尾 |
| char *const envp[] | 程序員自己組建環境變量,如果沒有則認為當前進程沒有環境變量,注意??環境變量也是以NULL結尾的 |
用下面的方法方便理解記憶:
三、它們之間的聯系
1.聯系:
從上圖可以看到所有的庫函數exec底層都是調用系統調用函數exeve函數
2.對于它們返回值的理解:
四、簡易的shell
#include <stdio.h> #include <sys/wait.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h>char g_command[1024];//該函數的功能是獲取命令行輸入的數據 int GetCommand() {//因為開始獲得的內存中的內容是不定的,所以使用前要先初始化memset(g_command,'\0',sizeof(g_command));//這里需要為'\0'留一個位置,不能把g_command全部用來讀取內容,否者就沒有結束標志,容易發生內存訪問越界if(fgets(g_command,sizeof(g_command)-1,stdin)==NULL){printf("fgets is error!\n");return -1;}//printf("g_command:%s\n",g_command);return 0; }//解析字符串 char** DealCommand(char* command) {if(command==NULL&&*command=='\0'){printf("dealcommand is error\n");return NULL;}//用來保存命令static char* argv[1024]={0};int argc=0;while(*command){//isspace函數用來去掉多余的空格//isspace的返回值:如果當前字符是空格返回1,否則返回0//注意'\0'在issapce函數中不算空格的,所以要進行判斷while(!isspace(*command)&&*command!='\0'){argv[argc]=command;argc++;//去找下一個空格while(!isspace(*command)&&*command!='\0'){command++;}*command='\0';}command++;}argv[argc]=NULL;//for(int i=0;i<argc;i++)//{// printf("%d:%s ",i,argv[i]);//}//printf("\n");return argv; }//進行程序替換 int exec() {char** argv=DealCommand(g_command);pid_t pid =fork();if(pid<0){printf("foek is error!\n");return -1;}else if(pid==0){//child//如果argc中為NULL,就直接返回if(argv[0]==NULL){exit(-1);}//進行替換,execvp第一個參數是可執行程序名,第二個參數是該可執行程序的參數組成的數組execvp(argv[0],argv);//execl("/usr/bin/ls","ls","-a",NULL);}else{//fatherwaitpid(pid,NULL,0);}return 0; }int main() {//循環讀數據while(1){printf("[dev@localhost dev]$ ");int ret = GetCommand();if(ret == -1){//如果讀取失敗,繼續循環讀取,不能直接break調continue;}//處理解析數據//char** argv = DealCommand(g_command);//進行替換//exec(argv);exec();}return 0; }總結
以上是生活随笔為你收集整理的进程间程序替换和minishell的全部內容,希望文章能夠幫你解決所遇到的問題。