1 exec函数组
-
返回值:
如果函数执行成功,不返回
如果函数执行失败,不需要判断返回值:可以直接打印输出,退出程序 -
exec函数族的[执行原理]
能够[替换]进程地址空间的[代码段.text] -
使用场景:
1.执行一个另外的程序不需要创建额外的地址空间
2.一个运行的程序a,想调用另外的应用程序b
2 函数介绍
int execl(const char *path, const char *arg, ...)
int execv(const char *path, char *const argv[])
int execle(const char *path, const char *arg, ..., char *const envp[])
int execve(const char *path, char *const argv[], char *const envp[])
int execlp(const char *file, const char *arg, ...)
int execvp(const char *file, char *const argv[])
------------------------
char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);
可执行文件查找方式、参数表传递方式、环境变量
[1]查找方式:上表其中前4个函数的查找方式都是完整的文件目录路径,而**后2个函数(以p结尾的两个函数)可以只给出文件名,系统就会自动从环境变量“$PATH”**所指出的路径中进行查找。
[2]参数传递方式:exec函数族的参数传递有两种方式—逐个列举/将所有参数整体构造成指针数组:
- 字母为“l”(list)的表示逐个列举的方式
- 字母为“v”(vertor)的表示将所有参数整体构造成指针数组传递,数组中的最后一个指针是NULL
[3]环境变量:exec函数族使用了系统默认的环境变量,也可以传入指定的环境变量。
- 以“e”(environment)结尾的两个函数execle、execve就可以在envp[]中指定当前进程所使用的环境变量替换掉该进程继承的所以环境变量。
[补充]PATH环境变量书写:用“:”分隔,以“.”号表示结束。例如:PATH=/bin:/usr/bin:
总结:exec函数族关系
- 前4位统一为:exec
- 第5位
l:参数传递为逐个列举方式:execl、execle、execlp
v:参数传递为构造指针数组方式:execv、execve、execvp - 第6位
e:可传递新进程环境变量:execle、execve
p:可执行文件查找方式为文件名:execlp、execvp
[1] execl
int execl(const char *path, const char *arg, …);
- path:可执行程序(绝对路径)
- 变参arg:要执行的程序需要的参数
- 第一arg:占位 # 可以随便写
- 后边的arg:命令的参数
- 参数写完之后:NULL结尾
例:execl("/bin/ls",“666”,"-lah",NULL);
[2] execlp
int execlp(const char *file, const char *arg, …); //p表示的含义是:PATH环境变量
execlp与execl不同点:执行PATH环境变量能够搜索到的程序,参数file只需要写(执行命令的名字)
[3] execv
int execv(const char *path, char *const argv[]);
- 参数:
path=/bin/ps #命令
char* args[]={“ps”,“aux”,NULL}; //
例:execv("/bin/ps",args);
综合案例
int main(){
for(int i=0;i<3;i++)
printf("i = %d\n",i);
pid_t pid = fork(); //创建子进程
if(pid<0){
perror("fork fail");
exit(1);
}
if(pid==0){ //在子进程中执行execl函数
sleep(1);
execl("/bin/ls","666","-lah",NULL); // 1 execl
/*
execlp("ls","666","-lah",NULL); // 2 execlp
*/
/*
char* buf[]={"ls","-lah",NULL};
execv("/bin/ls",buf); // 3 execv
*/
perror("execv");
exit(1);
}
for(int i=0;i<3;i++)
printf("__________i = %d\n",i);
return 0;
}
执行结果:
[gjw@localhost 3-exec]$ ./ls
i = 0
i = 1
i = 2
__________i = 0
__________i = 1
__________i = 2
[gjw@localhost 3-exec]$ 总用量 16K
drwxr-xr-x. 2 gjw gjw 31 10月 13 19:43 .
drwxr-xr-x. 5 gjw gjw 51 10月 13 19:20 ..
-rw-rw-r--. 1 gjw gjw 455 10月 13 19:45 execl.c
-rwxrwxr-x. 1 gjw gjw 8.5K 10月 13 19:43 ls
system()函数
int system(const char *command);
- 功能:system()函数调用“/bin/sh -c command”执行特定的命令,[阻塞当前进程直到command命令执行完毕]。
- 返回值:
- 如果无法启动shell运行命令,system将返回127;
- 出现不能执行system调用的其他错误时返回-1。
- 如果system能够顺利执行,返回那个命令的退出码。
示例代码1:使用system("ls *.c");
int main(){
system("ls *.c");
return 0;
}
示例代码2:system("ls *.c");的代码实现
int my_system(const char *command){
pid_t pid;
int status = 0;//0表示正常退出
if (command == NULL)
return -1;
if ((pid = fork()) < 0)//创建子进程失败
status = -1;//对应不能调用system的其他错误
else if (pid == 0){
/*利用exec函数族开启新程序*/
execl("/bin/sh", "sh", "-c", command, NULL);//exec只有错误才返回--此时表示system调用失败
exit(127);//不能执行shell返回127
}
else{
while (waitpid(pid, &status, 0) < 0)//避免僵尸进程
{
if (errno == EINTR)
continue;
status = -1;//没有可用子进程--system调用出错
break;
}
}
return status;//正常执行shell运行一个新程序
}
int main(){
my_system("ls *.c");
return 0;
}