Linux的学习之路:13、进程替代

news/2024/11/14 2:12:01/

摘要

本章主要是说一下进程替代用到的函数exec以及自己实现的简易shell

目录

摘要

一、进程程序替换

1、替换原理

2  、替换函数

3、函数解释与命令理解

4、代码演示

1、execl

2、execv

3、execlp

4、execvp

二、简易的myshell

三、代码 

myshell

exec


 

一、进程程序替换

1、替换原理

用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

也就是说可以利用一个函数进行控制另外一个函数,就像可以利用c语言写一个程序从而控制c++的程序,c++的写法也不需要我会,只需要给一个参数的传递,c++那边用自己的语法进行去编写就可以利用c语言进行控制了。

2  、替换函数

其实有六种以exec开头的函数,统称exec函数,这里是直接利用man指令进行查看,这里我是使用man 3 exec进行查看,但是刚开始我没有找到,然后发现是因为没有安装库函数包,下面这行代码是进行安装的。

sudo yum install man-pages

e05bc294eaa644428aa74892a568f6b2.png

3、函数解释与命令理解

这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。

命名理解如下:

l(list) : 表示参数采用列表

v(vector) : 参数用数组

p(path) : 有p自动搜索环境变量PATH

e(env) : 表示自己维护环境变量

4、代码演示

1、execl

 如上方函数的execl的使用如下方代码所示就是,个人上方手册查到的函数用法,execl就是需要绝对路径去进行访问使用,也就是环境变量,然后后面是指令使用,这里是利用ls指令进行演示的,

  1 #include <stdio.h>                                                                                                                                                                                            2 #include <stdlib.h>3 #include <unistd.h>4 #include <sys/wait.h>5 6 int main()7 {8     pid_t id=fork();9     if(id==0)10     {   //子进程11         printf("子进程开始运行,pid:%d\n",getpid());12         sleep(1);13         execl("/usr/bin/ls","ls","-a","-l",NULL);14         exit(1);15     }16     else17     {   //父进程18         printf("父进程开始运行,pid:%d\n",getpid());19         int status=0;20         pid_t id=waitpid(-1,&status,0);//阻塞等待,等到子进程死去,得到他的错误码21         if(id>0)22         {23             printf("wait success,exit code:%d\n",WEXITSTATUS(status));24         }25     }26     return 0;27 }
~

fc7c5cdbb949490a9ad2e779f45f179e.png

2、execv

这个函数后面是可以利用数组进行访问这个这个命令的指令,也就是可以用数组进行匹配使用。

 8 int main()9 {10     pid_t id=fork();11     if(id==0)12     {   //子进程13         printf("子进程开始运行,pid:%d\n",getpid());14         sleep(1);15         char *const _argv[NUM]=                                                                                                                                                                               16         {17             (char*)"-ls",18             (char*)"-a",19             (char*)"-l",20             NULL21         };22        // execl("/usr/bin/ls","ls","-a","-l",NULL);23         execv("/usr/bin/ls",_argv);24         exit(1);25     }26     else27     {   //父进程28         printf("父进程开始运行,pid:%d\n",getpid());29         int status=0;                                                                  30         pid_t id=waitpid(-1,&status,0);//阻塞等待,等到子进程死去,得到他的错误码31         if(id>0)                        32         {          33             printf("wait success,exit code:%d\n",WEXITSTATUS(status));34         }                            35     }                  36     return 0;                           37 }                      
~

e8ddb72bf6144169afb795ce94868d40.png

3、execlp

下方这块代码和execl使用方式差不多,但是有一点不同,就是环境变量的寻找这个不需要绝对路径。

 int main()9 {10     pid_t id=fork();11     if(id==0)12     {   //子进程13         printf("子进程开始运行,pid:%d\n",getpid());14         sleep(1);
W> 15         char *const _argv[NUM]=16         {17             (char*)"-ls",18             (char*)"-a",19             (char*)"-l",20             NULL21         };22        //execl("/usr/bin/ls","ls","-a","-l",NULL);23         execlp("ls","ls","-a","-l",NULL);24         //execv("/usr/bin/ls",_argv);                                                                                                                                                                       25         exit(1);26     }27     else28     {   //父进程29         printf("父进程开始运行,pid:%d\n",getpid());                                  30         int status=0;                             31         pid_t id=waitpid(-1,&status,0);//阻塞等待,等到子进程死去,得到他的错误码32         if(id>0) 33         {                                   34             printf("wait success,exit code:%d\n",WEXITSTATUS(status));35         }            36     }                                 37     return 0;        38 }

b0222c09fa5a4739a6749fa3944942ca.png

4、execvp

这里和上面execl差不多,但是也只需要相对路径就可以了,这里就演示了四个,后面两个用法就是按照手册进行更改就可以了。

8 int main()9 {10     pid_t id=fork();11     if(id==0)12     {   //子进程13         printf("子进程开始运行,pid:%d\n",getpid());14         sleep(1);15         char *const _argv[NUM]=16         {17             (char*)"-ls",18             (char*)"-a",19             (char*)"-l",20             NULL21         };22         //execl("/usr/bin/ls","ls","-a","-l",NULL);23         //execlp("ls","ls","-a","-l",NULL);24         //execv("/usr/bin/ls",_argv);25         execvp("ls",_argv);                                                                                                                                                                                   26         exit(1);27     }28     else   29     {   //父进程                                                                       30         printf("父进程开始运行,pid:%d\n",getpid()); 31         int status=0;                   32         pid_t id=waitpid(-1,&status,0);//阻塞等待,等到子进程死去,得到他的错误码33         if(id>0)                              34         {                            35             printf("wait success,exit code:%d\n",WEXITSTATUS(status));36         }                               37     }                  38     return 0;39 }                                                                  

33282689d44f43c287f7e319dad3c78a.png

 

二、简易的myshell

这里将实现一个简易的shell,shell读取新的一行输入,建立一个新的进程,在这个进程中运行程序 并等待这个进程结束。所以要写一个shell,需要循环以下过程:

1. 获取命令行

2. 解析命令行

3. 建立一个子进程(fork)

4. 替换子进程(execvp)

5. 父进程等待子进程退出(wait)

从而就可以拆分出下面几步

1. 打印出提示信息

2. 获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]

3. 命令行字符串解析:"ls -a -l -i" -> "ls" "-a" "-i"(这里完全可以利用strtok这个函数进行拆分字符串)

4. TODO,内置命令, 让父进程(shell)自己执行的命令,我们叫做内置命令,内建命令

5. fork()

也就是对应上面的五个过程,代码如下测试如下。

#include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 #include <sys/wait.h>5 #include <string.h>6 #include <sys/types.h>7 8 #define NUM 10249 #define SIZE 3210 #define SEP " "11 12 char cmd_line[NUM];13 char* g_argv[SIZE];14 15 int main()16 {17     while(1)18     {   //1、打印出信息提示19         printf("[root@localhost myshell]#");20         fflush(stdout);21         memset(cmd_line,'\0',sizeof cmd_line);22         //2、获取从键盘输入的各种数据23         if(fgets(cmd_line,sizeof cmd_line,stdin)==NULL)24         {25             continue;26         }27         cmd_line[strlen(cmd_line)-1]='\0';28         //3、命令字符串进行解析29         g_argv[0]=strtok(cmd_line,SEP);//第一调用,需要首先获取原始字符串30         int index=1;31         if(strcmp(g_argv[0], "ls") == 0)32         {
W> 33             g_argv[index++] = "--color=auto";34         }35         if(strcmp(g_argv[0], "ll") == 0)36         {
W> 37             g_argv[0] = "ls";
W> 38             g_argv[index++] = "-l";
W> 39             g_argv[index++] = "--color=auto";40         }
W> 41         while(g_argv[index++]=strtok(NULL,SEP));42         if(strcmp(g_argv[0], "cd") == 0) //not child execute, father execute                                                                                                                                43         {44             if(g_argv[1] != NULL) chdir(g_argv[1]); //cd path, cd ..45 46             continue;47         }48           pid_t id=fork();49         if(id==0)50         {51             printf("下面功能让子进程进程的\n");52             execvp(g_argv[0],g_argv);53             exit(1);54         }55         int status=0;56         pid_t ret=waitpid(id,&status,0);57         if(ret>0)printf("exit code:%d\n",WEXITSTATUS(status));58         59     }60     return 0;61 62 }

94a67dcb578f44148467a0bb356554d0.png

三、代码 

myshell

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>#define NUM 1024
#define SIZE 32
#define SEP " "char cmd_line[NUM];
char* g_argv[SIZE];int main()
{while(1){   //1、打印出信息提示printf("[root@localhost myshell]#");fflush(stdout);memset(cmd_line,'\0',sizeof cmd_line);//2、获取从键盘输入的各种数据if(fgets(cmd_line,sizeof cmd_line,stdin)==NULL){continue;}cmd_line[strlen(cmd_line)-1]='\0';//3、命令字符串进行解析g_argv[0]=strtok(cmd_line,SEP);//第一调用,需要首先获取原始字符串int index=1;if(strcmp(g_argv[0], "ls") == 0){g_argv[index++] = "--color=auto";}if(strcmp(g_argv[0], "ll") == 0){g_argv[0] = "ls";g_argv[index++] = "-l";g_argv[index++] = "--color=auto";}while(g_argv[index++]=strtok(NULL,SEP));if(strcmp(g_argv[2], "cd") == 0) //not child execute, father execute{if(g_argv[1] != NULL) chdir(g_argv[1]); //cd path, cd ..continue;}pid_t id=fork();if(id==0){printf("下面功能让子进程进程的\n");execvp(g_argv[0],g_argv);exit(1);}int status=0;pid_t ret=waitpid(id,&status,0);if(ret>0)printf("exit code:%d\n",WEXITSTATUS(status));}return 0;}

exec

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>#define NUM 10int main()
{pid_t id=fork();if(id==0){   //子进程printf("子进程开始运行,pid:%d\n",getpid());sleep(1);char *const _argv[NUM]={(char*)"-ls",(char*)"-a",(char*)"-l",NULL};//execl("/usr/bin/ls","ls","-a","-l",NULL);//execlp("ls","ls","-a","-l",NULL);//execv("/usr/bin/ls",_argv);execvp("ls",_argv);exit(1);}else {   //父进程printf("父进程开始运行,pid:%d\n",getpid());int status=0;pid_t id=waitpid(-1,&status,0);//阻塞等待,等到子进程死去,得到他的错误码if(id>0){printf("wait success,exit code:%d\n",WEXITSTATUS(status));}}return 0;
}

 

 


http://www.ppmy.cn/news/1431102.html

相关文章

IP证书怎么申请,如何实现加密保护

什么是IP SSL证书呢&#xff1f;简而言之&#xff0c;它是用来为网站提供加密保护的数字证书&#xff0c;确保用户与网站之间的通信不被第三方窃取或篡改。下面&#xff0c;让我们详细了解一下如何申请IP SSL证书以及实现加密保护的方法。 所谓IP SSL证书&#xff0c;是一种基…

如何用ServBay快速构建下一代GraphQL应用

在本指南中&#xff0c;我们将深入探讨如何利用ServBay一站式环境和Docker&#xff0c;构建可扩展的GraphQL微服务。我们将从微服务架构和GraphQL的基础知识入手&#xff0c;逐步深入到如何利用现代工具和技术构建、容器化并部署我们的微服务。 理解微服务架构 微服务架构是一…

数据结构与算法解题-20240422

这里写目录标题 一、2. 两数相加二、67. 二进制求和三、415. 字符串相加四、LCS 01. 下载插件五、71. 简化路径 一、2. 两数相加 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 …

AI原生技术分享活动:引领智能科技新浪潮

在这个数字化飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度改变着我们的生活。为了进一步推动AI原生技术的发展&#xff0c;我们举办了一场别开生面的技术分享活动&#xff0c;汇聚了众多行业专家和爱好者&#xff0c;共同探讨AI原生技…

ExcelVBA把当前工作表导出为PDF文档

我们先问问Kimi Excel导出为PDF的方法有多种&#xff0c;以下是一些常见的方法&#xff1a; 1 使用Excel软件的内置功能&#xff1a; 打开Excel文件&#xff0c;点击“文件”菜单。选择“另存为”&#xff0c;在“保存类型”中选择“PDF”。设置保存路径和文件名&#xff0c;点…

《神经网络与深度学习:案例与实践》动手练习1.3

飞桨AI Studio星河社区-人工智能学习与实训社区 动手练习1.3 执行上述算子的反向过程&#xff0c;并验证梯度是否正确。 import mathclass Op(object):def __init__(self):passdef __call__(self, inputs):return self.forward(inputs)# 前向函数# 输入&#xff1a;张量inpu…

网络安全数字孪生:一种新颖的汽车软件解决方案

摘要 随着汽车行业转变为数据驱动的业务&#xff0c;软件在车辆的开发和维护中发挥了核心作用。随着软件数量的增加&#xff0c;相应的网络安全风险、责任和监管也随之增加&#xff0c;传统方法变得不再适用于这类任务。相应的结果是整车厂和供应商都在努力应对汽车软件日益增加…

物联网通信中NB-IoT、Cat.1、Cat.M该如何选择?

物联网通信中NB-IoT、Cat.1、Cat.M该如何选择? 参考链接:物联网通信中NB-IoT、Cat.1、Cat.M该如何选择?​​ 在我们准备设计用于大规模联网的物联网设备时,选择到适合的LTE IoT标准将是我们遇到的难点。这是我们一开始设计产品方案就需要解决的一个问题,其决定我们设备需…