exec族函数、system函数、popen函数、PATH
exec族函數(shù)函數(shù)的作用:
我們用fork函數(shù)創(chuàng)建新進(jìn)程后,經(jīng)常會(huì)在新進(jìn)程中調(diào)用exec函數(shù)去執(zhí)行另外一個(gè)程序。當(dāng)進(jìn)程調(diào)用exec函數(shù)時(shí),該進(jìn)程被完全替換為新程序(在exec都后面的代碼不會(huì)被得到執(zhí)行)。因?yàn)檎{(diào)用exec函數(shù)并不創(chuàng)建新進(jìn)程,所以前后進(jìn)程的ID并沒(méi)有改變。
exec族函數(shù)功能:
在調(diào)用進(jìn)程內(nèi)部執(zhí)行一個(gè)可執(zhí)行文件。可執(zhí)行文件既可以是二進(jìn)制文件,也可以是任何Linux下可執(zhí)行的腳本文件。
函數(shù)族:
exec函數(shù)族分別是:execl, execlp, execle, execv, execvp, execvpe
函數(shù)原型:
#include <unistd.h> extern char **environ;int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg,..., 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[]);//使用較少返回值:
exec函數(shù)族的函數(shù)執(zhí)行成功后不會(huì)返回,調(diào)用失敗時(shí),會(huì)設(shè)置errno并返回-1,然后從原程序的調(diào)用點(diǎn)接著往下執(zhí)行。(errno這個(gè)值可以通過(guò)perror打印出來(lái))
參數(shù)說(shuō)明:
- path:可執(zhí)行文件的路徑名字
- arg:可執(zhí)行程序所帶的參數(shù),第一個(gè)參數(shù)為可執(zhí)行文件名字,沒(méi)有帶路徑且arg必須以NULL結(jié)束,例如:execl("./bin/echoarg",“echoarg”,“abc”,NULL) echoarg是可執(zhí)行文件名,abc是第一個(gè)參數(shù),最后必須以NULL結(jié)尾。
- file:如果參數(shù)file中包含/,則就將其視為路徑名,否則就按 PATH環(huán)境變量,在它所指定的各目錄中搜尋可執(zhí)行文件。
exec族函數(shù)參數(shù)極難記憶和分辨,函數(shù)名中的字符會(huì)給我們一些幫助:
- l : 使用參數(shù)列表
- p:使用文件名,并從PATH環(huán)境進(jìn)行尋找可執(zhí)行文件
- v:應(yīng)先構(gòu)造一個(gè)指向各參數(shù)的指針數(shù)組,然后將該數(shù)組的地址作為這些函數(shù)的參數(shù)。
- e:多了envp[]數(shù)組,使用新的環(huán)境變量代替調(diào)用進(jìn)程的環(huán)境變量
字符串轉(zhuǎn)整型:
#include <stdlib.h> int atoi(const char *nptr); long atol(const char *nptr); long long atoll(const char *nptr);示例代碼:
****execl代碼**** #include<stdio.h> #include <unistd.h> int main() {printf("before execl");if(execl("./number","number","12","13",NULL)==-1){printf("execl fail\n");perror("because");}printf("after execl");//因?yàn)閑xecl函數(shù)調(diào)用成功所以它之后的代碼就不再執(zhí)行。return 0; }****number可執(zhí)行文件代碼:**** #include<stdio.h> #include <stdlib.h> int main(int agrc,char*argv[3]) {printf("參數(shù)和為:%d\n",atoi(argv[1])+atoi(argv[2]));return 0; }可以通過(guò)whereis ls查看ls可執(zhí)行程序的位置: 上述程序中就可以替換為下列代碼——執(zhí)行l(wèi)s即可 execl("ls路徑","ls",NULL); 想用ls -l就可以在ls后面加參數(shù)即可: execl("ls路徑","ls","-l",NULL);獲取系統(tǒng)服務(wù)時(shí)間指令:date 同樣的道理可以用whereis date查看date可執(zhí)行程序的路徑 上述程序中就可以替換為下列代碼——執(zhí)行date即可 execl("date路徑","date",NULL);execl和execlp的區(qū)別在于:
exaclp函數(shù)帶p,所以能通過(guò)環(huán)境變量PATH查找到可執(zhí)行文件ps,當(dāng)可執(zhí)行文件的文件路徑中帶有 / 這種路徑符號(hào),我們將其視為路徑名(就是按照這個(gè)路徑去找可執(zhí)行文件),否則就將其視為環(huán)境變量(path變量的作用是可以讓我們?cè)跊](méi)有這個(gè)應(yīng)用的路徑下面打開(kāi)我們需要打開(kāi)的應(yīng)用,前提是這個(gè)應(yīng)用得在環(huán)境變量里面配置了路徑),在linux系統(tǒng)中可以用 echo $PATH 查看當(dāng)前的環(huán)境變量,那些冒號(hào)是分隔符。如果用execlp就可以寫為execlp(“date”,“date”,NULL);直接寫date就好。
環(huán)境變量和pwd顯示的路徑不一樣,只有將當(dāng)前路徑加入到環(huán)境變量的時(shí)候,環(huán)境變量里面才會(huì)出現(xiàn)當(dāng)前路徑,也就意味著在任何路徑下都可以訪問(wèn)該路徑下的可執(zhí)行文件。
PATH是什么?
如何修改環(huán)境變量?
在linux環(huán)境中可以通過(guò)以下代碼將路徑加入到環(huán)境變量:
帶v不帶l的一類exec函數(shù):
其實(shí)就是將execl可執(zhí)行程序里面的餐數(shù)放到指針數(shù)組里面,然后用數(shù)組的首地址代替可執(zhí)行程序名字和程序的參數(shù)。
示例:
char* canshu[]={"number","12","13","NULL"}; execv("./number",canshu)exec配合fork使用:
實(shí)現(xiàn)功能當(dāng)父進(jìn)程檢測(cè)到輸入為1的時(shí)候后,創(chuàng)建子進(jìn)程把配置文件的字段修改掉。
*********************** 以下是存在父子進(jìn)程的程序 通過(guò)調(diào)用現(xiàn)有的可執(zhí)行程序 修改目標(biāo)文件的內(nèi)容,他這個(gè) 要修改文件要加上絕對(duì)路徑 ************************ #include<stdio.h> #include <sys/types.h> #include <unistd.h> #include<stdlib.h> #include <sys/wait.h> int main() {pid_t pid;pid_t fpid,returnpid;int status;int input=0;int execlreturn=0;while(1){printf("請(qǐng)輸入數(shù)字:\n");scanf("%d",&input);if(input==1){fpid=fork();if(fpid>0){returnpid=waitpid(fpid,&status,0);if(WIFEXITED(status)){printf("子進(jìn)程正常退出,退出參數(shù)是:%d\n",WEXITSTATUS(status));}}if(fpid==0){execlreturn=execl("/home/fhn/linuxfile/changfile","changfile","/home/fhn/linuxfile/test.txt",NULL); if(execlreturn==-1){printf("exec fail\n");perror("execfail");}}}else{printf("do nothing\n");}}return 0; }system函數(shù):
#include <stdlib.h> int system(const char *command);函數(shù)說(shuō)明: system()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,由子進(jìn)程來(lái)調(diào)用/bin/sh-c string來(lái)執(zhí)行參數(shù)string字符串所代表的命令 此命令執(zhí)行完后隨即返回原調(diào)用的進(jìn)程。在調(diào)用system()期間SIGCHLD 信號(hào)會(huì)被暫時(shí)擱置,SIGINT和SIGQUIT 信號(hào)則會(huì)被忽略。sh -c就相當(dāng)于./ 就是為了執(zhí)行后面的指令string返回值: 如果fork()失敗 返回-1:出現(xiàn)錯(cuò)誤如果exec()失敗,表示不能執(zhí)行Shell,返回值相當(dāng)于Shell執(zhí)行了exit(127)如果執(zhí)行成功則返回子Shell的終止?fàn)顟B(tài)如果system()在調(diào)用/bin/sh時(shí)失敗則返回127,其他失敗原因返回-1。若參數(shù)string為空指針(NULL),則返回非零值。如果system()調(diào)用成功則最后會(huì)返回執(zhí)行shell命令后的返回值,但是此返回值也有可能為 system()調(diào)用/bin/sh失敗所返回的127,因此最好能再檢查errno 來(lái)確認(rèn)執(zhí)行成功。system調(diào)用結(jié)束后還會(huì)返回原程序繼續(xù)執(zhí)行system下面的代碼,而exec族函數(shù)不會(huì)。我的理解: 在system函數(shù)調(diào)用成功時(shí)返回進(jìn)程的狀態(tài)值 當(dāng)因shell不能執(zhí)行時(shí)也就是system()在調(diào) 用/bin/sh時(shí)失敗時(shí)返回127,其他失敗情況 返回-1,命令string為空指針(NULL)system 函數(shù)的返回值很簡(jiǎn)單明了,只有0和1。返回1, 表明系統(tǒng)的命令處理程序,即/bin/sh是可用的。 相反,如果命令處理程序不可用,則返回0。 在 判斷返回值時(shí)最好能再檢查errno來(lái)確認(rèn)執(zhí)行成功使用例子: system("/home/fhn/linuxfile/changfile /home/fhn/linuxfile/test.txt");popen函數(shù)和system函數(shù)區(qū)別?
popen函數(shù):
#include <stdio.h> FILE *popen(const char *command, const char *type); int pclose(FILE *stream);函數(shù)說(shuō)明:
- popen()會(huì)調(diào)用fork()產(chǎn)生子進(jìn)程,然后從子進(jìn)程中調(diào)用/bin/sh -c來(lái)執(zhí)行參數(shù)command的指令。
- 參數(shù)type可使用“r”代表讀取,“w”代表寫入。依照此type值,popen()會(huì)建立管道連到子進(jìn)程的標(biāo)準(zhǔn)輸出設(shè)備(比如說(shuō):ps指令,所以可以用“”r“”根據(jù)返回的指針讀取子進(jìn)程的標(biāo)準(zhǔn)輸出內(nèi)容)或標(biāo)準(zhǔn)輸入設(shè)備,然后返回一個(gè)文件指針。隨后進(jìn)程便可利用此文件指針來(lái)讀取子進(jìn)程的輸出設(shè)備或是寫入到子進(jìn)程的標(biāo)準(zhǔn)輸入設(shè)備中。
- 此外,所有使用文件指針(FILE*)操作的函數(shù)也都可以使用,除了fclose()以外。
- 如果 type 為 r,那么調(diào)用進(jìn)程讀進(jìn) command 的標(biāo)準(zhǔn)輸出。如果 type 為 w,那么調(diào)用進(jìn)程寫到 command 的標(biāo)準(zhǔn)輸入。
- popen比sysytem的好處是可以通過(guò)管道獲取運(yùn)行結(jié)果
返回值:
若成功則返回文件指針,否則返回NULL,錯(cuò)誤原因存于errno中。
注意:
popen()會(huì)繼承環(huán)境變量,通過(guò)環(huán)境變量可能會(huì)造成系統(tǒng)安全的問(wèn)題。
為什么要用popen函數(shù):
#include<stdio.h> #include <stdlib.h> int main() {system("ps");return 0; }這幾行代碼的運(yùn)行結(jié)果如下: fhn@ubuntu:~/jincheng$ ./popen PID TTY TIME CMD20157 pts/3 00:00:03 bash24755 pts/3 00:00:00 popen24756 pts/3 00:00:00 sh24757 pts/3 00:00:00 ps如果想要把它運(yùn)行的結(jié)果放到文件或者字符串中去 就要用到popen函數(shù)將結(jié)果流入到文件中去,如下面代碼: #include<stdio.h> #include <stdlib.h> #include <unistd.h> int main() {char* buf;FILE* fd;int n_read;buf=(char*)malloc(1024);fd=popen("ps","r");n_read=fread(buf,1,1024,fd);pclose(fd);printf("管道輸出:%s",buf);return 0; } 以下是輸出結(jié)果:fhn@ubuntu:~/jincheng$ ./popen 管道輸出: PID TTY TIME CMD20157 pts/3 00:00:03 bash24865 pts/3 00:00:00 popen24866 pts/3 00:00:00 sh24867 pts/3 00:00:00 ps如果有將信息流入到內(nèi)存而不打印則屏幕上面沒(méi)有顯示。注意popen用的是fread、fwrite而不是read和write,因?yàn)閞ead返回的是文件描述符不符合,fread返回的是文件指針
總結(jié)
以上是生活随笔為你收集整理的exec族函数、system函数、popen函数、PATH的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: cmd 文本文件分割_通过split命令
- 下一篇: oracle数据库实例,数据库的理解