进程(11)进程替换函数详解

本章目标

1.进程替换函数

1.进程替换函数

在前面我们已经介绍了进程替换的原理,在这里我们介绍这个进程替换函数

我们先介绍这六个

1.execl

execl他有一个参数,第一个是表示它要替换的函数的路径,后面的是这个函数要怎么样的去执行,说白话就是你在shell上如何去写的,在这里就如何去填写.这里面用了一个可变参数,因为对于一个程序来说,它的选项的个数是不确定的.但是无论这个参数有多些它的最后一个参数永远都是以NULL为结尾的.

c 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
int main()
{
	pid_t id = fork();
	if(id==0)
	{
		execl("/usr/bin/ls","ls","-a","-l",NULL);
		
	}
	else
	{
		int stat = 0;
		pid_t rid = waitpid(id,&stat,0);
		if(rid==id)
		{
			printf("success\n");
		}
	}
	return 0;
}

结果和我们之前演示的一样

2.execlp

这个函数与上面函数的区别是,我们第一个参数不需要去传路径了,我们只需要传我们要执行的命令是什么,当我们进程程序替换的时候,它回去PATH环境变量里面进行匹配.

二者的区别就是这一个

c 复制代码
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>
int main()
{
        pid_t id = fork();
        if(id==0)
        {
                execlp("ls","ls","-a","-l",NULL);

        }
        else
        {
                int stat = 0;
                pid_t rid = waitpid(id,&stat,0);
                if(rid==id)
                {
                        printf("success\n");
                }
        }
        return 0;
}
~    

结果是一样的,这里面要注意的问题就是,我们有的时候第二个参数是可以省略的,shell会自己进行补充,但是我们不推荐这种写法,会增加记忆成本不说,对于后面的东西我们也不好解释

3.execle

这个与第一个相比,它是允许我们自定义环境变量的,我们下面演示下

c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
        const char* env[]=
        {
                "PATH=/home/mutou/code/linux-c/exectest",
                NULL

        };
        pid_t id =fork();
        if(id==0)
        {
                execle("/home/mutou/code/linux-c/exectest/tmp/test1","test1",NULL,env);
                exit(1);

        }
        else
        {
                int stat = 0;
                pid_t rid = waitpid(id,&stat,0);
                if(id==rid)
                {
                        printf("exit code->%d\n",WEXITSTATUS(stat));

                }

        }
        return 0;
}
c 复制代码
#include<stdio.h>
int main(int argc,char* argv[],char* env[])
{
	int i = 0;
	for(;env[i];i++)
		printf("%s\n",env[i]);
	return 0;
}

我们在另一个文件中接受这个环境变量.然后打印

成功替换

4.execv

这个与第一个的区别是,它可以传一个参数表进去,我们可以在调用前就可以实现这个东西该如何调用.剩下的与第一个使用方法没有区别.我们带l就是可变参数,v可以把它理解成为向量表.

我们下面写一个例子演示下

c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
        char* argv[] =
        {
                "ls",
                "-a",
                "-l",
                NULL
        };
        pid_t id = fork();
        if(id==0)
        {
                execv("/usr/bin/ls",argv);
                exit(1);
        }
        else
        {
                int stat = 0;
                pid_t rid = waitpid(id,&stat,0);
                if(rid==id)
                {
                        printf("exit code->%d\n",WEXITSTATUS(stat));
                }
        }
        return 0;
}

5.execvp

这个带p都是从环境变量当中找,我们不需要指定路径

和上面的execlp是一样的.其他的用法与execv是一致的.

c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
        char* argv[] =
        {
                "ls",
                "-a",
                "-l",
                NULL
        };
        pid_t id = fork();
        if(id==0)
        {
                execvp(argv[0],argv);
                exit(1);
        }
        else
        {
                int stat = 0;
                pid_t rid = waitpid(id,&stat,0);
                if(rid==id)
                {
                        printf("exit code->%d\n",WEXITSTATUS(stat));
                }
        }
        return 0;
}

我们在这里不省略的参数的好处是向这种直接传一个数组的,带环境变量我们可以直接用命令行参数表的第一个元素传进去.

6.execvpe

显而易见这个是用向量表同时可以从环境变量当中找路径

我们现在演示两个版本

第一个传父进程的环境变量去找

第二个覆盖原来的环境变量

该一下环境变量,不会的可以参考我往期的博客.

c 复制代码
        {
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/mutou/code/linux-c/exectest/tmp",
                NULL

        };
        extern char** environ;
        pid_t id = fork();
        if(id==0)
        {
                execvpe((const char*)argv[0],argv,environ);
                exit(1);
        }
        else
        {
                int stat = 0;
                pid_t rid = waitpid(id,&stat,0);
                if(rid==id)
                {
                        printf("exit code -> %d\n",WEXITSTATUS(stat));
                }
        }
        return 0;
        }

我们下面修改一下改成我们自己的环境变量

c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	char* argv[]=
	{
		"test1"
		,"-a"
		,"-l"
		,NULL
	};
	char* env[]=
	{
		"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/mutou/code/linux-c/exectest/tmp",
		NULL

	};
	extern char** environ;
	pid_t id = fork();
	if(id==0)
	{
		execvpe((const char*)argv[0],argv,env);
		exit(1);
	}
	else
	{
		int stat = 0;
		pid_t rid = waitpid(id,&stat,0);
		if(rid==id)
		{
			printf("exit code -> %d\n",WEXITSTATUS(stat));
		}
	}
	return 0;
}

同样可以跑

7.exec系列命名规则和参数解释

1.exec系列的函数,有很多

他们会按照以下规则组合

1.l表示使用参数列表

2.v表示使用数组

3.e表示需要自行组装环境变量

4.p表示会自己去寻找路径,从环境变量当中匹配

l和v是对立的,二者只会出现一个

exec系列的函数成功是没有返回值的

失败会将错误码设置为-1

这6个函数实际上都是库函数

他们调用都是execve这个系统调用,因为程序替换会有很多应用场景,所以库函数对其封装了很多个版本的,对于不需要自行传环境变量的版本,默认都是用的environ这个环境变量

8.exec调用其他解释性语言的程序或者shell脚本

python解释器或者是shell,我们都是他们的程序也要变成进程去执行,那么我们的exec函数自然可以进行调用我们下面用python和shell脚本分别实验

c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	char* argv[]=
	{
		"bash",
		"test.sh",
		NULL
	};
	pid_t id = fork();
	if(id==0)
	{
		execvp(argv[0],argv);
		exit(1);
	}
	else
	{
		int stat = 0;
		pid_t rid = waitpid(id,&stat,0);
		if(rid==id)
		{
			printf("exit code is %d\n",WEXITSTATUS(stat));
		}
	}
	return 0;
}
c 复制代码
#!/bin/bash



echo "aaaaaaaaaaaa"
c 复制代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	char* argv[]=
	{
		"python3",
		"/home/mutou/code/linux-c/exectest/tmp/test.py",
		NULL
	};
	pid_t id = fork();
	if(id==0)
	{
		execvp(argv[0],argv);
		exit(1);
	}
	else
	{
		int stat = 0;
		pid_t rid = waitpid(id,&stat,0);
		if(rid==id)
		{
			printf("exit code is %d\n",WEXITSTATUS(stat));
		}
	}
	return 0;
}
python 复制代码
#!/bin/python3


print("aaaaaaa")

成功运行,要注意python的解释器用不了bash的环境变量,要指定具体路径,PATH这个环境变量是只针对可执行文件的.我们这里面的是脚本文件,bash找不到文件会从PATH中找但是python3用不了.

相关推荐
Q741_14710 小时前
C++ 队列 宽度优先搜索 BFS 力扣 429. N 叉树的层序遍历 C++ 每日一题
c++·算法·leetcode·bfs·宽度优先
say_fall10 小时前
微机原理:微型计算机基础
服务器·网络·单片机·微机原理
CSDN_RTKLIB10 小时前
CMake成果打包
c++
ben9518chen10 小时前
Linux文件系统基础
linux·服务器·php
晴天¥10 小时前
计算机网络-Linux配置-DNS解析/为什么会出现ping: www.baidu.com: 未知的名称或服务
linux·运维·计算机网络
Yu_Lijing10 小时前
基于C++的《Head First设计模式》笔记——工厂模式
c++·笔记·设计模式
十五年专注C++开发10 小时前
CMake进阶:核心命令get_filename_component 完全详解
开发语言·c++·cmake·跨平台编译
代码游侠10 小时前
应用——Linux FrameBuffer图形显示与多线程消息系统项目
linux·运维·服务器·开发语言·前端·算法
Caitlin_lee_10 小时前
计算机网络期末复习SCAU-第六章
运维·服务器·计算机网络