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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux系统【二】exec族函数及应用

發布時間:2023/11/30 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统【二】exec族函数及应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文件描述符

文件描述符表是一個指針數組,文件描述符是一個整數。
文件描述符表對應的指針是一個結構體,名字為file_struct,里面保存的是已經打開文件的信息

需要注意的是父子進程之間讀時共享,寫時復制的原則是針對物理地址而言的,通過程序操控虛擬地址的我們是無法查別到這個問題的,其中的機理由MMU進行控制(詳見我的上一篇博客:Linux系統【一】CPU+MMU+fork函數創建進程)

測試程序:

#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<sys/wait.h> #include<sys/types.h>int main() {int *t = (int*)malloc(sizeof(int));*t = 0;printf("parent process:&t=%p\n",t);pid_t pid;pid = fork();if(0 == pid){printf("child process:&t=%p\n",t);(*t)++;printf("child process:&t=%p\n",t);printf("child process:t=%d\n",*t);}else{wait(NULL);printf("parent process:&t=%p\n",t);printf("parent process:t=%d\n",*t);}return 0; }

運行結果:

exec函數族

fork創建子進程后執行的是和父進程相同的程序(有可能執行不同的代碼分支),子進程往往要調用一種exec函數來執行另一個程序,當進程調用一種exec函數時,該進程的用戶空間代碼和數據完全被新程序替換,從新程序的啟動例程(簡單來講就是main函數,實際上是一個由匯編和C混合編寫的程序)。調用exec并不創建新進程,所以調用exec前后進程的id并未改變

命令行執行程序的實質其實就是fork+exec

#include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, .../* (char *) NULL */); int execlp(const char *file, const char *arg, ... //第一個參數為可執行文件的文件名,后面的參數是命令行參數/* (char *) NULL */); int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execvpe(const char *file, char *const argv[],char *const envp[]);
  • l list 命令行參數列表
  • p PATH 搜索file時使用PATH變量
  • v vector 使用命令行參數數組
  • e environment 使用環境變量數組,不適用進程原有的環境變量,設置新加載程序運行的環境變量

execlp

調用程序的時候會搜索一遍環境變量,如果在環境變量中可以找到程序就會執行,否則按照路徑運行程序。

#include<stdio.h> #include<unistd.h> #include<stdlib.h>int main() {pid_t pid;pid = fork();if(-1 == pid){perror("fork error:");exit(1);}else if(0 == pid){execlp("ls","ls","-l","-a",(char *)NULL);}else{sleep(1);printf("Parent");}return 0; }

這里解釋一下上述程序:execlp函數第一個參數是調用的程序,從第二個參數開始是命令行參數,最后一定要以(char*)NULL結尾才能正常運行。其中比較特殊的是命令行參數的第一個參數是什么不重要,我上面雖然寫的是ls,但其實隨便寫什么都可以。

為什么會有這種寫什么都可以的情況出現呢?實際原因是:我們在執行程序的時候系統會默認帶有一個參數(雖然這個參數大多數情況下都與程序名相同,但是某些shell會將此參數設置為完全的路徑名),所以我們第一個參數是不會有作用的,真正有作用的參數是從參數數組中第一個元素開始的。

例如:

//test.c #include<stdio.h>int main(int argc,char* args[]) {for(int i=0;i<=argc;++i){printf("%d=[%s]\n",i,args[i]);}return 0; }

將上面兩個程序組合:

#include<stdio.h> #include<unistd.h> #include<stdlib.h>int main() {pid_t pid;pid = fork();if(-1 == pid){perror("fork error:");exit(1);}else if(0 == pid){execlp("./test","first","second","third",(char *)NULL);printf("Child\n");}else{sleep(1);printf("Parent\n");}return 0; }


我們可以發現一旦運行execlp將不會再運行原來進程后面的代碼,原本進程的代碼塊完全被新的文件代替

execl

不會查找環境變量,直接按照路徑運行程序

execle

需要借助環境變量表char ** environ

execv

傳入的需要是一個字符串數組,而不能直接傳命令行參數

例題:將當前系統中的進程信息打印到文件中

#include<stdio.h> #include<stdlib.h> #include<unistd.h>int main(int argc,char *argv[]) {if(argc != 2){printf("you should input filename\n");exit(1);}freopen(argv[1],"w",stdout);execlp("ps","ps","aux",(char*)NULL);return 0; }

更好的做法是使用dup2函數(其中的2的意思是to,如果后面是4的話意思常常是for),并將新進程放在子進程中

dep2(old fd,new fd); // 將舊文件描述符中的內容拷貝到新文件描述符中 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h>int main(int argc,char *argv[]) {if(argc != 2){printf("you should input filename\n");exit(1);} // freopen(argv[1],"w",stdout);int fd = open(argv[1],O_CREAT | O_RDWR,06444);if(-1 == fd){perror("openfile error:");exit(1);}dup2(fd,STDOUT_FILENO);pid_t pid=fork();if(-1 == pid){perror("fork error:");exit(1);}else if(0 == pid){execlp("ps","ps","aux",(char*)NULL);perror("exec error:"); //不需要判斷返回值,如果成功不會運行下面的語句exit(1);}else{close(fd);}return 0; }

需要注意的是使用dup2函數以后原本標準輸出文件指針丟失了,如果還要回到標準輸出文件,應該之前用dup保存一份,使用之后再dup2回去就可以了。

exec函數族沒有成功返回值,只有失敗返回值

總結

以上是生活随笔為你收集整理的Linux系统【二】exec族函数及应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。