exec族函数函数的作用:
我们用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序(在exec都后面的代码不会被得到执行)。因为调用exec函数并不创建新进程,所以前后进程的ID并没有改变。
exec族函数功能:
在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数族:
exec函数族分别是:execl, execlp, execle, execv, execvp, execvpe
函数原型:
#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函数族的函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。(errno这个值可以通过perror打印出来)
参数说明:
exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:
字符串转整型:
#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");//因为execl函数调用成功所以它之后的代码就不再执行。 return 0; } ****number可执行文件代码:**** #include<stdio.h> #include <stdlib.h> int main(int agrc,char*argv[3]) { printf("参数和为:%d\n",atoi(argv[1])+atoi(argv[2])); return 0; } 可以通过whereis ls查看ls可执行程序的位置: 上述程序中就可以替换为下列代码——执行ls即可 execl("ls路径","ls",NULL); 想用ls -l就可以在ls后面加参数即可: execl("ls路径","ls","-l",NULL); 获取系统服务时间指令:date 同样的道理可以用whereis date查看date可执行程序的路径 上述程序中就可以替换为下列代码——执行date即可 execl("date路径","date",NULL);
execl和execlp的区别在于:
exaclp函数带p,所以能通过环境变量PATH查找到可执行文件ps,当可执行文件的文件路径中带有 / 这种路径符号,我们将其视为路径名(就是按照这个路径去找可执行文件),否则就将其视为环境变量(path变量的作用是可以让我们在没有这个应用的路径下面打开我们需要打开的应用,前提是这个应用得在环境变量里面配置了路径),在linux系统中可以用 echo $PATH 查看当前的环境变量,那些冒号是分隔符。如果用execlp就可以写为execlp(“date”,“date”,NULL);直接写date就好。
环境变量和pwd显示的路径不一样,只有将当前路径加入到环境变量的时候,环境变量里面才会出现当前路径,也就意味着在任何路径下都可以访问该路径下的可执行文件。
PATH是什么?
如何修改环境变量?
在linux环境中可以通过以下代码将路径加入到环境变量:
方法一: export PATH=$PATH:当前路径 $PATH表示当前环境变量 //配置完后可以通过echo $PATH查看配置结果。 生效方法:立即生效 有效期限:临时改变,只能在当前的终端窗口中有效,当前窗口关闭后就会恢复原有的path配置 用户局限:仅对当前用户 方法二: 通过修改.bashrc文件: vim ~/.bashrc //在最后一行添上: export PATH=/usr/local/mongodb/bin:$PATH 生效方法:(有以下两种) 1、关闭当前终端窗口,重新打开一个新终端窗口就能生效 2、输入“source ~/.bashrc”命令,立即生效 有效期限:永久有效 用户局限:仅对当前用户 方法三: 通过修改profile文件: vim /etc/profile /export PATH //找到设置PATH的行,添加 export PATH=/usr/local/mongodb/bin:$PATH 生效方法:系统重启 有效期限:永久有效 用户局限:对所有用户 方法四: 通过修改environment文件: vim /etc/environment 在PATH=”/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games”中加入“:/usr/local/mongodb/bin” 生效方法:系统重启 有效期限:永久有效 用户局限:对所有用户
带v不带l的一类exec函数:
其实就是将execl可执行程序里面的餐数放到指针数组里面,然后用数组的首地址代替可执行程序名字和程序的参数。
示例:
char* canshu[]={"number","12","13","NULL"}; execv("./number",canshu)
exec配合fork使用:
实现功能当父进程检测到输入为1的时候后,创建子进程把配置文件的字段修改掉。
*********************** 以下是存在父子进程的程序 通过调用现有的可执行程序 修改目标文件的内容,他这个 要修改文件要加上绝对路径 ************************ #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("请输入数字:\n"); scanf("%d",&input); if(input==1){ fpid=fork(); if(fpid>0){ returnpid=waitpid(fpid,&status,0); if(WIFEXITED(status)){ printf("子进程正常退出,退出参数是:%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函数:
#include <stdlib.h> int system(const char *command); 函数说明: system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令 此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。 sh -c就相当于./ 就是为了执行后面的指令string 返回值: 如果fork()失败 返回-1:出现错误 如果exec()失败,表示不能执行Shell,返回值相当于Shell执行了exit(127)如果执行成功则返回子Shell的终止状态 如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。 如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为 system()调用/bin/sh失败所返回的127,因此最好能再检查errno 来确认执行成功。 system调用结束后还会返回原程序继续执行system下面的代码,而exec族函数不会。 我的理解: 在system函数调用成功时返回进程的状态值 当因shell不能执行时也就是system()在调 用/bin/sh时失败时返回127,其他失败情况 返回-1,命令string为空指针(NULL)system 函数的返回值很简单明了,只有0和1。返回1, 表明系统的命令处理程序,即/bin/sh是可用的。 相反,如果命令处理程序不可用,则返回0。 在 判断返回值时最好能再检查errno来确认执行成功 使用例子: system("/home/fhn/linuxfile/changfile /home/fhn/linuxfile/test.txt");
popen函数和system函数区别?
popen函数:
#include <stdio.h> FILE *popen(const char *command, const char *type); int pclose(FILE *stream);
函数说明:
返回值:
若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
注意:
popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
为什么要用popen函数:
#include<stdio.h> #include <stdlib.h> int main() { system("ps"); return 0; } 这几行代码的运行结果如下: fhn@ubuntu:~/jincheng$ ./popen PID TTY TIME CMD 20157 pts/3 00:00:03 bash 24755 pts/3 00:00:00 popen 24756 pts/3 00:00:00 sh 24757 pts/3 00:00:00 ps 如果想要把它运行的结果放到文件或者字符串中去 就要用到popen函数将结果流入到文件中去,如下面代码: #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; } 以下是输出结果: fhn@ubuntu:~/jincheng$ ./popen 管道输出: PID TTY TIME CMD 20157 pts/3 00:00:03 bash 24865 pts/3 00:00:00 popen 24866 pts/3 00:00:00 sh 24867 pts/3 00:00:00 ps 如果有将信息流入到内存而不打印则屏幕上面没有显示。
注意popen用的是fread、fwrite而不是read和write,因为read返回的是文件描述符不符合,fread返回的是文件指针