【Linux】进程替换

(一)进程替换

  • 进程替换不会创建新的进程,进程PCB未发生改变,进程实体(数据代码内容)被替换
  • 进程替换成功后不会执行替换函数下的代码,失败后会执行
  • 进程替换成功不返回,失败后返回-1

(二)环境变量

  • 环境变量的作用:

当使用shell来运行一个程序时,若没有加绝对路径,系统先会在当前路径下寻找该程序,若没找到就会去环境变量中去寻找该程序。都没找到就会报没有该指令的错误。

jiege@ubuntu:~/Desktop/code/c$ pwd
/home/jiege/Desktop/code/c
jiege@ubuntu:~/Desktop/code/c$ which gcc
/usr/bin/gcc
jiege@ubuntu:~/Desktop/code/c$ echo $PATH
/home/jiege/tools/nodejs/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
jiege@ubuntu:~/Desktop/code/c$ 

  • 查看所有的环境变量
#include <stdio.h>

int main(int arg, char* argv[], char* envp[])
{
	int i = 0;
	while(envp[i] != NULL)
	{
		printf("%s\n", envp[i++]);
	}

	return 0;
}

结果:

请添加图片描述


(三)进程替换API(unistd.h)

exec族函数参数极难记忆和分辨,函数名中的字符会给我们一些帮助:

  • l : 使用参数列表
  • p:使用文件名,并从PATH环境进行寻找可执行文件
  • v:应先构造一个指向各参数的指针数组,然后将该数组的地址作为这些函数的参数。
  • e:多了envp[]数组,使用新的环境变量代替调用进程的环境变量
(1)系统调用API
 #include <unistd.h>

int  execve(const char *pathname, char *const argv[],
                  char  *const envp[]);

(2)库函数API
  • int execl(const char* pathname, const char* arg, .../*(char*)NULL*/);

    参数解释:目标程序的进程替换

    • pathname:目标程序的路径
    • arg:执行这个程序的方式
    • 返回值:失败-1
    • 例如:execl("/bin/ls", "ls" "-a", "-l", (char*)NULL);

  • int execlp(const char *file, const char *arg, .../* (char*) NULL */);

    参数解释:该函数会在环境变量的路径中查找file

    • file:要执行的目标程序
    • arg:传给目标程序的参数
    • 返回值:失败-1
    • 例如:execlp("ls", "ls", "-a", "-l", (char*)NULL);
    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
    	printf("hello\n");
    
    	execlp("ls", "ls", "-a", "-l", (char*)NULL);
    	printf("world\n");
    	return 0;
    }
    
    • 结果:
    jiege@ubuntu:~/Desktop/test$ vim main.c
    jiege@ubuntu:~/Desktop/test$ gcc -o main main.c
    jiege@ubuntu:~/Desktop/test$ ./main
    hello
    总用量 24
    -rwxrwxr-x 1 jiege jiege 16736 129 20:12 main
    -rw-rw-r-- 1 jiege jiege   148 129 20:12 main.c
    jiege@ubuntu:~/Desktop/test$ 
    

  • int execle(const char *pathname, const char *arg, .../* (char*) NULL, char *const envp[] */);

    参数解释:给这个目标进程传入指定envp的环境变量

    • pathname:目标程序的路径

    • arg:替换后如何执行的方式,envp表示要导入的环境变量

    • 例:

      • 程序myenv输出未设置环境变量的变量
      #include <stdio.h>
      #include <stdlib.h>
      
      int main()
      {
      	printf("myenvp: %s\n", getenv("MYENVP"));
      	return 0;
      }
      
      • 结果

      请添加图片描述

    • 程序b再使用进程替换给a程序传入环境变量
    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
    	char* buff[] = {"MYENVP=/home/jiege/awei", NULL};
    	execle("./myenv", "myenv", NULL, buff);
    	perror("execle err");
    	return 0;
    }
    
    • 结果

    请添加图片描述

    注意:envp数组前的参数是NULL,envp数组最后一个元素为NULL,并且该操作会覆盖原环境变量的值


  • int execv(const char *pathname, char *const argv[]);

    参数详解:

    • pathname:目标程序路径名/usr/...
    • argv:将所有的执行方式存放在argv指针数组中
    • 例:
    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char* argv[])
    {
    	char* buff[] = {"ls", "-l", NULL};
    
    	execv("/usr/bin/ls", buff);
    	perror("execv err");
    	return 0;
    }
    
    • 结果:

    请添加图片描述


  • int execvp(const char *file, char *const argv[]);

    参数详解:给目标程序传入参数

    • file:被执行的目标程序

    • argv:传给file程序的参数

    • 例:使用程序a中替换成程序b,b将得到的参数打印

      • a.c

        #include <stdio.h>
        #include <unistd.h>
        
        int main()
        {
        	printf("A start execvp\n");
        	char* argv[] = {"hello", "world", NULL};
        
        	execvp("./b", argv);
        	perror("execvp err");
        	return 0;
        }
        
      • b.c

        #include <stdio.h>
        #include <unistd.h>
        
        int main(int argc, char* argv[])
        {
        	int i = 0;
        	while(argv[i] != NULL)
        	{
        		printf("%s\n", argv[i++]);
        	}
        	return 0; 
        }
        
    • 结果:

    请添加图片描述


  • int execvpe(const char *file, char *const argv[], char *const envp[]);

    参数详解:

    • file:目标程序
    • argv:函数参数
    • envp:环境变量

(四)进程替换和fork的结合使用案例

  • 一个例子:就比如bash窗口中输入ps -f指令,查看当前进程的完整格式
jiege@ubuntu:~$ ps -f
UID          PID    PPID  C STIME TTY          TIME CMD
jiege       2680    2669  0 14:28 pts/0    00:00:00 bash
jiege      11269    2680  0 17:07 pts/0    00:00:00 ps -f
jiege@ubuntu:~$ 
  • 分析:

    可以看到ps -f这个进程的进程号PID是11269,它的父进程的进程号PPID是2680;而2680就是bash这个进程。

  • 结论:

    bash就是这个shell窗口的进程的名字,当你输入ps -f时,bash这个进程就fork一个子进程,子进程进程替换执行ps -f命令,将此时的结果输出给父进程bash,父进程输出打印结果

(五)进程替换测试

  • 代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
	printf("pid of main: %d\n", getpid());

	//进程替换
	execl("/bin/ps", "ps", "-f", (char*)NULL);
	perror("exec err");
	
	exit(0);
}
  • 执行结果
jiege@ubuntu:~/Desktop/code/exec$ ./main
pid of main: 11556
UID          PID    PPID  C STIME TTY          TIME CMD
jiege       9970    2669  0 14:28 pts/1    00:00:00 bash
jiege      11556    9970  0 17:50 pts/1    00:00:00 ps -f
jiege@ubuntu:~/Desktop/code/exec$ 

  • 结果分析:

    • 在bash中执行./main时,bash进程fork出子进程,子进程替换成main程序,main程序中再进行进程替换成ps -f程序

(六)进程替换API总结

函数名参数传递形式路径是否导入环境变量
execl列表需要可执行程序路径不导入 使用当前环境变量
execlp列表默认在环境变量中找不导入 使用当前环境变量
execle列表需要可执行程序路径导入 使用导入的环境变量
execv数组需要可执行程序路径不导入 使用当前环境变量
execvp数组默认在环境变量中找不导入 使用当前环境变量
execve数组需要可执行程序路径导入 使用导入的环境变量
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值