目录

进程程序替换

1.进程替换的原理

2.怎么来另起炉灶执行另一个程序

①execl

②execv

③execlp

④execvp​编辑

⑤execle

⑥execvpe 和 execve

3.执行一下自己的程序

4.丐版shell

①显示提示符

②获取用户输入​编辑

③.将字符串切分

④.创建子进程,执行

⑤.程序替换

⑥内建命令


进程程序替换

先前,我们可以用fork()创建一个子进程,子进程代码继承父进程代码,执行跟父进程相同的代码,我们能不能让子进程离经叛道,另起炉灶干一番事业,脱离父进程的束缚,当然欧克啦。

我们可以让它执行c/c++、Java、Php、shell、Python呀什么的...可神奇了。

1.进程替换的原理

在没有让子进程另起炉灶之前,没有写时拷贝时,他们是这样存在的。

突然,子进程撂挑子了。来了个b.exe就把他拐跑了

原理就是:

①.将磁盘的程序,加载到内存结构中。

②.页表重新建立映射,指向另一块加载了程序的内存空间。(让父子进程彻底分离,再也没有关系,让子进程执行一个新的程序)((>_<)变心了明明)

2.怎么来另起炉灶执行另一个程序

当然还是要借助他人的援手,上述替换的过程都是由操作系统来完成,所以我们要借助os之手,分离他们,我们来学习第一个函数接口。这些函数都是系统调用。

①execl

程序替换:

1.调用函数去替换,第一步我们已经做好了。

2.接下来就是要找这个程序在哪,这便是第一个参数所要干的事情。

3.我们找到了程序之后,需要程序怎么做,这是第二个参数要干的。第二参数是可变参数,我们可以不拘泥于传一个参数。比如我们想执行ls这个进程(ls为什么是进程,因为在命令行上启动的进程都是BASH进程的子进程),我们可以传 ls,也可以传ls -a,可以传ls -a -l,还可以传ls -a -l -i。命令行上怎么打,就怎么传,当然要有标识程序执行完毕的NULL放在最后。

我们来试试:

结果如下图:

哟,到这大家有没有发现一个问题,最后一个printf没有打印这是为什么呢?

因为execl一旦替换成功,execl以下的代码要全部被替换,printf被替换走了,当然执行不了。

这个execl函数,有返回值,那我们要不要关注返回值呢?

根本就不用,函数成功之后都会直接执行要执行的进程,就不会有返回值。失败了,execl后面的代码就不会被替换,自然会执行后面的代码。一旦执行后面的代码,只有一种结果,程序替换失败了。然后通过返回值判断什么原因导致失败。

先前这些都是自己的进程去替换执行一个进程,execl后面的代码不会执行,接下来咋们要通过子进程,来执行一个进程,让子进程被拐走,不影响父进程的代码。

代码如下:

结果如图: 

成功证明子进程跑了(>_<)、

大家有没有注意为什么退出码是零,明明我设置了退出码是12呀。

因为上文说过一旦执行另一个进程,下面的代码都会被替换,这时exit(12)已经没有了,这时接收的返回值是execl执行完 ls -l -a 这个进程的退出码。注意,我是让子进程去替换进程(执行一个新的进程),对父进程没有任何影响,这全然是因为写实拷贝的作用。上文有讲。

②execv

它和execl没有本质的区别

execl: “l” 是list 链表

execv:“v” 是vector 数组

path:需要执行的程序的位置

argv[]:刚刚是可变参数(arg ...),现在是数组。

意味着我们可以这样:将数组传给第二个参数

我们传入数组结果是相同的:

③execlp

我觉得挺好用的一个同类型的函数。

它命名中的“p”,指的是path 环境变量,意味着我们不用去明确的输入目标进程的地址,我们只用输入想执行的进程,前提是这个进程在你所在的环境变量目录中,这样os才能找到,目标的进程。

代码如下:

结果如下:

千万要注意,一定要写NULL,来指明进程执行完毕。

不然会成这样:

这里如愿的拿到了12这个退出码,说明execlp这个函数寄了,进程没执行成功。

④execvp

大同小异,这就不细讲了

⑤execle

用这个函数,我们可以将环境变量传给将要执行的进程。

代码如下:

这是父进程:

这是要被执行的进程:

结果如下:

要注意我们的PATH会将原本进程的PATH给覆盖掉。

我们如果用execl的话,不传MYPATH,它自己的PATH会打印出来。

我们用excele

将自己的MYPATH传过去,PATH将会被覆盖

后面的MYPATH也打不出了。

我们要想PATH被打出,自己的MYPATH也被打出,可以这样:

然后在父进程中这样写:        这样就成功咯,大家可以私下试试

⑥execvpe 和 execve

这俩和上面的都大同小异。

exec +l/v(链表or数组) +p(可以不输入地址直接输入进程名称) +e(可以自己传环境变量给子进程)

3.执行一下自己的程序

其实上面有两个实例我已经用子进程去调用自己的程序了,下面正式说一下。

平常用vs不能直接运行两个exe,今天我们用一个进程去调动另一个进程。

其中的一个circulate 程序:

我们要用test的子进程去调用circulate 

黄天不负有心人,我们这里的WEXITSTATUS(status)终于能获得我们设置的退出码了,关于退出码,上一篇文章有讲。

结果:

成功了,当然也可以去调动Java、Python呀什么的程序。大家可以去尝试下。

4.丐版shell

虽然是精简版,但是它可以创建 终止 等待 程序替换。

这些是头文件和宏定义:

①显示提示符

②获取用户输入

哎?为什么会换两次行,我明明printf中只有一个\n。

因为,我们再输入命令的时候,最后都要敲一个回车,来表示执行DOS命令。

这个回车(不可见字符)自然也被存到了command_line字符数组中。

我们可以做的操作就是将这个回车符赋值为‘\0’。

这样就不会换行了。

③.将字符串切分

因为我们平常输入的命令之间都是带有空格的。比如:ls -a -l。

strtok函数可以让字符串以指定的分隔符分开。

while的循环条件很怪,为什么要这样写呢?

strtok函数截取成功,返回字符串起始地址。

截取失败返回NULL,正好赋给command_args。

那为什么在循环条件中的strtok中第一个参数要传NULL?

strtok的函数原型为char *strtok(char *s, char *delim),功能为“Parse S into tokens separated by characters in DELIM.If S is NULL, the saved pointer in SAVE_PTR is used as the next starting point. ” 翻译:作用于字符串s,以包含在delim中的字符为分界符,将s切分成一个个子串;如果,s为空值NULL,则函数保存的指针SAVE_PTR在下一次调用中将作为起始位置。                                                                                                                                                  (摘自百度百科)

意味着,我第一次用传要分隔的字符串,第二次及以后如果传入NULL,那么函数的上一次保存的地址将在下一次调用作为起始地址。

我们将分割好的字符串打印一下:

结果是:

④.创建子进程,执行

⑤.程序替换

将上面我们所学的内容汇聚在一起,以及上一篇文章的内容。

这一切尽在代码中,我们实测一下效果。

⑥内建命令

在我们的shell里,通过cd .. 去回到上一级目录的方法是不可行的。        ​​​​

我们通过exec*去执行cd命令,只是让子进程的路径发生变化,之后子进程运行结束,接下来通过“pwd”这个进程来查看当前路径,当前路径没有发生任何变化。因为这时的路径是通过父进程继承下来的,执行cd命令的进程只是改变了自己的进程,然而对父进程的路径发生不了改变。要想改变成功,只能通过在父进程中执行内建命令。一些命令只能通过父进程执行,不能让子进程执行,这就是内建命令。

我们修改下代码:在分隔开字符串之后,去判断是否要求子进程进行cd

之后使用chdir函数

传入想转换到的路径,执行成功后,会使调用者的当前路径变成传入的路径。

我们看下效果:

同样:

export也是一个内建命令。它的作用是在系统环境变量中,导入自己的环境变量。

在环境变量中就能看到,我们导入的环境变量。

看看在我们的shell中行不行,不用实验肯定不行,环境变量具有全局属性,它可以被子进程继承。在我们的shell中,用一个子进程去导入环境变量,只会将环境导入子进程的所处的环境变量之中。根本不会修改父进程的环境变量。

我们在父进程修改下,让我们自己的shell也能添加环境变量。

putenv是一个将传入参数加入环境变量的函数。

为什么还是不行?

因为,系统的环境变量在char**数组中,是全局的,被系统所维护。而我们的环境变量在我们的command_args中,但是我们shell是循环执行,我们是将所要的环境变量导出了,但是到下一次我们又去执行新的子进程时,comman_args又被清空了,当然环境变量也没了。如何改变,其实可以很简单,我们可以在循环外面定义一个数组将我们的环境变量存起来,无论怎么循环,都影响不到全局变量。

成功了!

我们的简易shell到此就完善的差不多了,希望以后有机会,还能再次完善他,感谢观看,我们下次再见。

下面是simpleshell的所有代码:至于编译时会warning,不用在乎,能成功运行。

进程程序替换((>_<)子进程跑了),模拟编写一个入门shell相关推荐

  1. Linux-进程控制详解(进程创建+进程终止+进程等待+进程程序替换)

    Linux进程控制 1. 进程创建 1.1 fork 1.2 vfork 2. 进程终止 3. 进程等待 3.1 为什么要进程等待 3.2 wait 3.3 waitpid 3.4 获取子进程退出信息 ...

  2. Linux系统编程18:超详解进程程序替换exec函数的一些用法

    文章目录 (1)进程程序替换是什么 (2)exec-替换函数 (3)实例展示-了解exec函数的替换原理 A:execl和execv B:execlp和execvp C:替换自己的程序和execle ...

  3. 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换

    目录 1.进程创建 1)重温fork():让正在运行的进程创建出来一个子进程:从已存在的进程中创建一个新的进程,新进程为子进程而远进程为父进程. 2)fork内部完成的事情 3)用户空间 & ...

  4. [Linux-进程控制] 进程创建进程终止进程等待进程程序替换简易shell

    [Linux-进程控制] 进程创建&进程终止&进程等待&进程程序替换&简易shell 进程创建 fork函数回顾 双返回值 为什么要给子进程返回0,给父进程返回子进程的 ...

  5. Java黑皮书课后题第6章:*6.15(金融应用:打印税表)程序清单3-5给出了计算税款的程序。使用下面的方法体编写一个计算税款的方法。使用这个方法编写程序,打印可征税人从50000到60000间隔

    *6.15(金融应用:打印税表)程序清单3-5给出了计算税款的程序.使用下面的方法体编写一个计算税款的方法.使用这个方法编写程序 题目 题目描述 破题 程序清单3-5(非本题):代码不全 补充代码:编 ...

  6. python的简单程序代码_小白学编程?从一个简单的程序开始学习Python编程

    笔者思虑再三还是决定选择图文(因为百家的视频发布画质真不怎么样[囧]). 笔者学习编程的时间也挺长的,因为业余,因为时间不多,各种原因,自学编程的路特别难走.然后笔者发现,自己能为小白贡献一些力量,然 ...

  7. bash 将二进制转换为十进制_用‘栈的思想编写一个十进制转换二进制、八进制或十六进制的程序...

    用'栈'的思想编写一个十进制转换二进制.八进制或十六进制的程序 根据进制转换方法,如十进制向二进制转换,将转换的十进制整数除以二进制基数(2),得到余数和商,如果商不为0,该商继续做被除数,除以基数, ...

  8. 定义并调用函数 十进制转二进制_用‘栈的思想编写一个十进制转换二进制、八进制或十六进制的程序...

    用'栈'的思想编写一个十进制转换二进制.八进制或十六进制的程序 根据进制转换方法,如十进制向二进制转换,将转换的十进制整数除以二进制基数(2),得到余数和商,如果商不为0,该商继续做被除数,除以基数, ...

  9. python脚本编写_如何用Python包编写一个简单的脚本,表达你对父母的爱?

    全文共2800字,预计学习时长6分钟 在繁忙的工作生活中,我们经常忘记给所爱的人发WhatsApp.本教程将使用Python包Twilio编写一个简单的Python脚本来发送WhatsApp消息.我们 ...

最新文章

  1. What do you need at home?
  2. .net源代码已经可以调试
  3. C++易于实现的有趣项目【附上完整教程】
  4. python @staticmethod和@classmethod的作用
  5. java web: Servlet JSP MVC
  6. nodejs mysql 创建连接池
  7. python输出字符串的后两位_Python字符串三种格式化输出
  8. 单片机c语言数码显示实验报告,单片机动态显示技术实验报告.doc
  9. myeclipse 8.5最新注册码(过期时间到2016年)
  10. 在.NET Core中使用MySQL5.7的JSON类型字段
  11. LeetCode 566 Reshape the Matrix 解题报告
  12. XP停止服务,共建网络安全大环境
  13. html日历框架,日历.html
  14. Corel VideoStudio X7 (64bit)安装
  15. 怎样设置路由器禁用其他设备
  16. LeetCode-1873. 计算特殊奖金
  17. 工程师的基本功是什么?如何练习?—学习心得分享
  18. Unity 多机器的视频不卡帧同步
  19. 一口“臊子面”的背后,是西安小吃产业发展的缩影
  20. Shutdown自定义自动关机软件

热门文章

  1. 阿里云 访问控制RAM
  2. 想做一个完美的健身训练计划,你需要知道什么?
  3. 工具栏浏览器主页被篡改修复方法
  4. 全生命周期大数据处理系列
  5. 时间戳与普通日期的相互转换
  6. You got to put the past behind you before you can move on
  7. 如何将一个Python脚本加入Windows右键菜单?
  8. 关于5G技术和应用场景的简单介绍
  9. 这些数据泄露方式,80%的企业不易发现
  10. abaqus运行报错 WindowsError:[Error 2]