【Linux】进程程序替换 &&简易mini_shell实现

替换原理

目前,我们使用fork创建子进程,为了用if,else让子进程执行父进程代码的一部分。如果想让子进程执行一个全新的程序,进程不变,仅仅替换当前进程的代码和数据,就叫做 进程替换

在这里插入图片描述

子进程往往要调用一种exec函数,执行另一个程序,当进程调用一种exec函数时。进程的用户空间代码和数据被新程序完全替换。调用exec函数前后进程的id不变。

程序替换的本质:把指定的代码和数据,加载到特定进程的上下文中。
C/C++程序要运行,必须通过 加载器先加载到内存。
方式:exec*程序替换函数。

替换函数

在Linux下使用man 3 exec查看:
在这里插入图片描述

在这里插入图片描述

六种函数都是以exec开头的吗,称为exec函数。

exec函数的返回值:
成功时,函数不返回。失败时,函数返回-1。

-> 所以exec函数只有出错的返回值而没有成功的返回值。只要exec*返回了,就一定时因为调用失败了。

替换函数的使用

execl:
int execl(const char *path, const char *arg, ...);

path:要执行的目标程序的全路劲,所在路径/文件名形式,来表示你要执行谁
arg:表示你要执行的目标程序在命令行上怎么执行,这里的参数就怎么一个一个的传递进去,和命令行上的形式一样!
… :因为时可变参数列表,所以必须用NULL结尾!

接下来看7个函数原型:

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int execve(const char* path, char* const argv[], char* const envp[]);

简单的理解方法:

l:表示arg参数用列表传,const char* arg, ...

在这里插入图片描述
v:arg参数用数组传,char* const argv[]

在这里插入图片描述

p:有p自动搜索环境变量 PATH,不需要自己写路径。

在这里插入图片描述

e:自己维护环境变量(自定义环境变量)

所有的接口,差别并不大,只是参数不同。设置这么多接口,是为了满足不同的应用场景。

在这里插入图片描述
在这里插入图片描述

只有execve时真正的系统调用,其他五个函数最终都调用execve,在man手册用 man 2 exec可以查看,其他函数在man 3 exec可以查看。

execve的demo:

char *env[] = {
    "MYENV1_xxxxxxxxxxxxxxxxxxxxxxxxxx",
    NULL
  };

execle("./myload", "myload", NULL, env);

简易shell实现程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>

#define NUM 128
#define CMD_NUM 64

int main()
{
  char command[NUM];
  for(; ;)
  {
    char *argv[CMD_NUM] = {NULL};
    // 1、打印提示符
    command[0] = 0; //用这种方式,可以做到O(1)时间复杂度,清空字符串
    printf("[zjy@myhostname mydir]# ");
    fflush(stdout);
    // 2、获取命令字符串
    fgets(command, NUM, stdin);
    command[strlen(command)-1] = '\0';
    printf("echo: %s\n", command);
   
    // ls -a -l -d\0
    // 3、解析命令字符串  strtok
    const char *sep = " ";
    argv[0] = strtok(command, sep);
    int i = 1;
    while(argv[i] = strtok(NULL, sep))
    {
      ++i;
    }

    // 4、检测命令是否是需要shell本身执行的,内建命令
    if(strcmp(argv[0], "cd") == 0)
    {
      if(argv[1] != NULL)
        chdir(argv[1]);
        continue;
    }

    // 5、执行第三方命令
    if(fork() == 0)
    {
      // child
      execvp(argv[0], argv);
      exit(1);
    }

    // father
    waitpid(-1, NULL, 0);
    
    
    // for(i=0; argv[i]; ++i)
    // {
    //   printf("%s\n", argv[i]);
    // }
    

  }
  return 0;
}

注意点:

fork()执行的命令是第三方命令(独立的),但是cd不是,cd回退只是子进程回退,但是当子进程结束后,父进程还在原来的路径下,所以这时,不能创建子进程,要让父进程自己执行,可以调用 chdir函数。不能用程序替换,如果使用,会导致整个代码发生改变,不能继续循环输入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JoyCheung-

赏颗糖吃吧~~~

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

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

打赏作者

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

抵扣说明:

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

余额充值