程序替换接口
程序替换
- 程序替换
- main 函数回顾说明
- 程序替换
- execve 指定运行参数argv
- execvp 不需要指定环境变量
- execv
- execl 、execlp 、execle
- 程序替换的作用
- 小点点
程序替换
main 函数回顾说明
main(int argc,char* argv[],char* env[])
argc:程序运行参数的个数
argv:程序运行参数,字符指针数组,最后一个参数之后,以NULL结尾
env:程序的环境变量,字符指针数组,最后一个参数之后,以NULL结尾
程序替换
execve 指定运行参数argv
int execve(char* path,char* argv[],char* env[]);
功能: 将 path 这个路径名所指定的程序加载到内存中,然后让当前进程调度管理这个程序的运行
argv:用于设定这个程序的运行参数
env:用于设定这个程序的环境遍历
返回值:替换成功运行新程序 没有返回值;失败返回-1
使用示例:
// execve.c 程序
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("这是我程序运行的起始位置~\n");
char* argv[]={"-a","-d","-c","xzz",NULL}; //argv 字符函数必须以 NULL 结尾
char* env[]={"MYVAL=999","CLASS=98",NULL};
//进行程序替换,argc 程序替换运行当前程序
execve("./argc",argv,env);
//execve("/bin/ls",argv,env); //指定系统调用接口路径,指定运行参数和环境变量
return 0;
}
其中所调用的 argc 程序:
//argc.c 程序
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc,char* argv[],char* env[])
{
int i=0;
for(;argv[i]!=NULL;++i) //将运行参数打印
printf("argv[%d]=[%s]\n",i,argv[i]);
printf("~~~~~~~~~~~~~~~~~~\n");
i=0;
for(;env[i]!=NULL;++i) //打印环境变量
printf("env[%d]=[%s]\n",i,env[i]);
return 0;
}
运行结果:
execvp 不需要指定环境变量
int execvp(char* file,char* argc[],cahr* env);
第一个参数不用指定路径,默认会在 PATH环境变量指定的路径下找
环境变量默认使用当前已有的,不用手动设置环境变量
使用示例:
int main()
{
printf("这是我程序运行的起始位置~\n");
//char* argv[]={"-a","-d","-c","xzz",NULL}; //argv 字符函数必须以 NULL 结尾
//char* env[]={"MYVAL=999","CLASS=98",NULL};
// execve("./argc",argv,env);
char *argv[]={"ls","-l",NULL};
char* env[]={NULL};
//使用运行参数 argv 中 ls -l 替换当前程序
execvp("ls",argv);
//env 默认采用已有的环境变量,且不需要指定路径
//execvp("./argc",argv);
// 等价于 execve("ls",argc,env-main中第三个参数)
printf("这是我程序运行的终止~~~\n");
return 0;
}
execv
int execv(char* path,char* argv[]);
不用设置环境变量,但是需要路径
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main()
{
printf("这是我程序运行的起始位置~\n");
char *argv[]={"ls","-l",NULL};
execv("ls",argv); //不指定路径时会发生错误
perror("execv error\n");
printf("这是我程序运行的终止~~~\n");
return 0;
}
当没有指定 ls 的位置时,会发生替换失败:
当指定路径之后:
execv("/bin/ls",argv);
execv(“bin/ls”,argv); 需要指定路径
execvp(“ls”,argv); 不需要指定路径
execve(“bin/ls”,argv,env); 手动设置环境变量,并且需要指定路径
execl 、execlp 、execle
上述三种替换每次都需要定义一个参数字符指针数组,比较麻烦,因此常会这三种替换函数:
int execl(char* path,…/char arg*/);
int execlp(char* file,…);
int execle(char* path,…,char* env[]);
使用示例:
execlp("ls","ls","-l",NULL) //可以不指定环境变量
execle("bin/ls","ls","-l",NULL,env) //需要指定环境变量以及系统调用接口的路径
程序替换的作用
shell 是一个命令行解释器,捕捉用户的输入信息,了解用户想要干什么,然后执行对应的shell指令--------系统内核与用户之间沟通的桥梁
(1)父进程捕捉用户输入 [ ls -l -a ];
(2)解析输入,得到命令名称,各个参数 [ls] [-l] [-a];
(3)创建子进程;
(4)对子进程进行程序替换,将子进程要进行调度的程序换成要执行的 shell 指令程序;
(5)父进程等待子进程退出(等待指令执行完毕----避免僵尸进程),然后捕捉用户的下一个输入。
小点点
wc -l :统计个数(行数统计)
du :查看磁盘空间
pstree :查看目录的树形结构
Q1:不算main函数进程,一一共创建了多少个进程?
Q2:请问打印了多少个 * ?
int main()
{
for(int i=0;i<2;++i){
fork();
printf("*\n");
}
return 0;
}
答案:6个
存在 \n 说明会刷新缓冲区,因此创建子进程时不会复制父进程内容(*)
Q3:请问打印了多少个 * ?
int main()
{
for(int i=0;i<2;++i){
fork();
printf("*");
}
return 0;
}
答案:8个
不存在 \n 说明不会刷新缓冲区,因此 * 不会打印,暂时存储在缓冲区里,因此创建子进程会同时复制父进程缓冲区中内容(*)