冰冰学习笔记:进程程序替换

欢迎各位大佬光临本文章!!!

还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正。

本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬、帅哥、美女点点支持,您的每一分关心都是我坚持的动力。

我的博客地址:bingbing~bang的博客_CSDN博客https://blog.csdn.net/bingbing_bang?type=blog

我的gitee:冰冰棒 (bingbingsupercool) - Gitee.comhttps://gitee.com/bingbingsurercool


系列文章推荐

冰冰学习笔记:《内存地址空间》

冰冰学习笔记:《进程控制》


目录

系列文章推荐

前言

1.替换原理

2.替换函数

3.MiniShell的实现


前言

        我们之前使用fork函数创建子进程来执行父进程中不同的代码逻辑,父子进程之间代码共享,数据写时拷贝。但是如果我们想让子进程不执行父进程的代码,去执行一个全新的程序那应该如何做到呢?这就需要使用进程程序替换函数来做到。

1.替换原理

        什么是进程的程序替换呢?简单来说就是父进程创建的子进程想要拥有独立的代码和数据,之前父子进程之间是代码共享,数据各自拥有,现在子进程需要使用特定的接口重新加载磁盘上新的代码和数据,但是并不会重新创建进程,内核数据结构还是原来子进程拥有的,只是页表映射关系发生了改变!

2.替换函数

        进程程序替换的函数具有多个,每个函数之间使用方式大体相同,但是有些细微的差距。

int  excel (const char* path, const char * arg, ...);

返回值:整形,函数调用成功并不会返回,调用失败返回-1

参数:第一个参数表示进程的路径,第二个参数表示进程的名称,后面的为可变参数列表,

           表示传入选项,最后一个参数必须是NULL。

        简单来说,我们调用进程替换函数传参时,我们在命令行上怎么执行的,这里就怎么填写。

        但是,通过上面的程序替换结果,我们会发现,为什么原来程序的打印语句少了一个?“当前进程的结束代码”并没有被打印。

        原因在于excel是程序替换,调用函数成功,会将当前进程的所有代码和数据都会替换,包含已经执行过的或者未执行的代码, 原程序后面的代码不会在执行。调用失败原程序不会被替换,将继续执行。

        这也就说明了为什么execl函数没有调用成功的返回值,因为根本不会有人去接收。所以我们应该在调用后面直接用进程退出函数退出即可,一旦调用错误,直接退出。

        所以我们一般都会创建子进程去进行程序替换,父进程来接受子进程的状态,就算子进程调用失败也不会影响父进程,父进程可以继续工作。

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

该函数与execl不同的地方在于第一个参数不用指定路径,只需要指定进程名称,它会自己从环境变量PATH中寻找。

        进程替换程序不仅可以调用系统命令程序,也可以调用我们自己写的程序,例如调用我们自己写的python程序,test.py。 

        所以exec类型的函数实际上就是加载器的底层接口!

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

该函数的第一个参数也是需要指定路径,但是第二个参数需要传递一个指针数组,数组里面存放是调用程序的名字和命令。

  

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

与上面的函数的区别是不需要传递路径,会自己去环境变量中寻找

int execle(const char* path, const char *arg, ... , char* const envp[ ]); 

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

这两个函数可以向目标进程传递环境变量

        例如我们调用我们自己写的子进程,里面打印出父进程自定义的环境变量就可以使用这个函数。

        除了以上几个函数,操作系统还提供了一个函数execve函数,上面的函数都是经过封装后,底层调用的这个函数进行任务执行。

3.MiniShell的实现

        既然学习了进程替换的函数,现在我们可以使用该函数进行一个minishell的建立,让其能够简单的实现shell的部分功能,并且能简单的运行起来。

        我们发现,shell在执行命令的时候,shell本身不会受到影响,这是因为shell是通过创建子进程来实现命令的执行。在子进程中利用替换函数,将对应的命令执行程序替换到当前子进程中,从而完成命令的执行。

        因此我们也可以使用这种方式来实现自己的shell。

        首先,shell一旦运行起来就不会退出,因此我们需要父进程一直执行,所以我们通过fork函数来创建子进程来执行对应的命令。在执行之前,我们首先需要接受输入的参数并且将其解析出来。

        由于shell输入的参数是直接在命令提示行之后的,所以我们不能直接使用换行符刷新提示符。输入的参数中我们是要敲一下回车才能输入,但是命令执行时的字符串是不能有回车符的,所以也要去除。

最终执行结果如下所示:

        接下来就是对命令字符串的分解了,我们使用库函数strtok利用输入的空格进行打断,并且将打断的结果字符串存放到指针数组g_argv中。

        strtok函数的使用要注意,第一次使用时传入的是原始字符串,再次调用时需要传递空指针。

        字符串解析完毕后,剩下的就是创建子进程并执行程序替换,将我们解析的字符串对应的命令一一执行。最后使用父进程接受状态。

        这里要注意一点,执行cd命令并不能创建子进程进行执行,因为目录的跳转是父进程之间的跳转,所以我们需要使用父进程自己进行命令的执行,需要调用系统接口函数进行实现。 

        当我们想设置环境变量时,就需要特殊的设置,我们需要先将解析的环境变量的字符串保存起来,避免地址被清空覆盖,然后再将对应的环境变量使用putenv函数进行设置,但是设置之前需要先将环境变量environ引进来。 

这样我们就能实现基本的shell模拟实现了。 

代码链接:minishell的实现 · 643ba4a · 冰冰棒/Linux - Gitee.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bingbing~bang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值