【Linux】进程控制 — 进程程序替换 + 实现简易shell

这篇具有很好参考价值的文章主要介绍了【Linux】进程控制 — 进程程序替换 + 实现简易shell。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

📖 前言

上一节我们讲了进程终止和进程等待等一系列问题,并做了相应的验证,本章将继续对进程控制进行学习,我们将学习进程程序替换,进行相关验证,运用系统进程程序替换接口,自己模拟写一个shell,该shell能够实现执行指令,等一系列命令行操作……


1. 进程程序替换

1.1 程序替换的概念:

概念引入:

将可执行程序加载到内存,并且重新调整子进程的页表映射,使之指向新的进程的代码和数据段,这种过程就叫做程序替换。

子进程执行的是父进程的代码片段,那么如果我们想让创建出来的子进程,执行全新的程序呢?

此时就要用到:进程的程序替换。

1.2 为什么要程序替换:

原因:

  • 原因是我们想让我们的子进程执行一个全新的程序。
  • 不同语言写的功能互相调用,这就是为什么要有程序替换的原因。

我们一般在服务器设计(Linux编程)的时候,往往需要子进程干两件种类事情:

    • 1.让子进程执行父进程的代码片段(服务器代码)
    • 2.让子进程执行磁盘中一个全新的程序(shell, 想让客户端执行对应的程序,通过我们的进程,执行其他人写的进程代码等等)C/C++ -> C/C++/Python/Shell/Php/Java…

1.3 程序替换的原理:

程序替换的原理:

  • 将磁盘中的程序,加载入内存结构。
  • 重新建立页表映射,谁执行程序替换,就重新建立子进程的映射关系。

效果:让我们的父进程和子进程彻底分离,并让子进程执行一个全新的程序!

父进程的映射关系:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
程序替换之后,子进程的映射关系:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
调整子进程的页表,让其不再与父进程代码和数据有任何关系,而是指向自己的代码和自己的数据区。

注意:

  • 请问:这个过程有没有创建新的讲程呢?
  • —— 没有!!!

小结:

  • 说白了就是让fork创建子进程,不想让子进程执行父进程代码片段。
  • 我们想让子进程执行磁盘当中全新的程序,而且我们没有创建新的进程。
  • 因为子进程的内核数据结构基本没变,只是重新建立了虚拟到物理的映射关系罢了。
  • 包括子进程的PID都不变,压根就没有创建新的进程,只不过让新的进程执行了不同的程序罢了。

每一个进程都有自己的CPU上下文,进程切换时会保存CPU数据。

2. 六个exec替换函数

上述我们讲了什么是程序替换,下面就要来见见猪跑了。
程序替换是由操作系统完成的,调用系统调用接口来完成操作。

  • 我们如果想执行一个全新的程序,我们需要做几件事情:
  • 先找到这个程序在哪里? —— 程序在那里
  • 程序可能携带选项进行执行(也可以不携带) —— 怎么执行

明确告诉OS,我想怎么执行这个程序是什么,要不要带选项。
我们平时在命令行中敲的指令都是一个一个可执行程序。

  • 程序替换的是子进程:(重点)
  • 进程替换永远影响的是进程的本身,子进程的替换永远不会影响父进程,因为进程具有独立性。
  • 独立性体现在内核层面,不同进程有不同的地址空间,有不同的页表替换只是加入新的代码和数据。
  • 重新建立的是页表映射但并不影响内核数据结构的具体情况。
  • 子进程虽然和父进程代码共享数据写实拷贝,但是一旦发生进程替换了,就认为代码和数据发生了双写实拷贝,就彻底将两个进程分开了。
  • 所以引入子进程的原因就是,一方面把需求做到位,另一方面不影响父进程,因为父进程可能还要接收新的命令,再去执行新的程序。

六个exec替换函数:

【Linux】进程控制 — 进程程序替换 + 实现简易shell

2.1 execl函数:

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

path:

  • 这个是路径,可执行程序的路径。

arg:

  • 命令行怎么写(1s -1 -a), 这个参数就怎么填"ls",“-l”,“-a”,最后必须是NULL结尾
  • 标识 “如何执行程序的” 参数传递完毕

… :

  • 可变参数,可以传多个参数

第一个参数是解决了,程序在哪里的问题,第二个参数往后所有的参数,解决的都是程序如何执行的问题。

代码演示:

#include <stdio.h>
#include <unistd.h>

int main()
{
    //让我的程序执行系统上的: ls -a -i这样的一个命令
    printf("我是一个进程,我的pid是 : %d\n", getpid());

    //int ret = execl("/usr/bin/ls", "ls", "-l", "-a", NULL); //带选项
    //execl("/usr/bin/top", "top", NULL); //不带选项
    //execl("/usr/bin/which", "which", "pwd", NULL); //不带选项

    //下面这行代码没有打印出来
    //一旦代码执行到这里,必然是进程替换失败了
    
    //替换失败的情况
    int ret = execl("/usr/bin/lsssss", "ls", "-l", "-a", NULL); //带选项
    printf("我执行完毕了,我的pid : %d, ret = %d\n", getpid(), ret);

    return 0;
}

一旦进程替换成功了,就不会再执行程序替换函数以后的代码了,因为直接去是该进程被替换掉了。

【Linux】进程控制 — 进程程序替换 + 实现简易shell
显而易见,代码中程序替换以后的打印内容并没有显示出来,说明进程替换以后的代码压根就没执行,而是去执行ls进程了。

总结:

  • 一旦替换成功,是将当前进程的代码和数据全部替换了!!
  • 前一个printf被执行是因为程序替换并没有执行。
  • 所以替换上面的代码依旧是当前进程执行执行,execl之后代码就不复存在了。

所以程序替换不用判断返回值:

不需要返回值,一旦有值返回那么必然是返回失败了!!!因为只要成功了,就不会有返回值,而失败的时候,必然会继续向后执行!!最多通过返回值得到什么原因导致的替换失败!

引入进程创建:

  • 子进程执行程序替换,会不会影响父进程呢??
    • 不会(因为进程具有独立性)
  • 为什么,如何做到的??
    • 数据层面发生写时拷贝!
    • 当程序替换的时候,我们可以理解成为,代码和数据都发生了写时拷贝完成父子的分离!

【Linux】进程控制 — 进程程序替换 + 实现简易shell)

2.2 execv函数:

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

实现的功能和execl一模一样。

path:

  • 这个是路径,可执行程序的路径。

argv[]:

  • 如何执行,和execl的唯一区别就是传参方式的不一样

【Linux】进程控制 — 进程程序替换 + 实现简易shell
代码演示:

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

int main()
{
    printf("我是父进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        //我们要子进程执行全新的程序,以前我们是子进程执行父进程的代码片段
        
        printf("我是子进程,我的pid是:%d\n", getpid());
        //char* const argv_[] = {
        //    (char*)"ls",
        //    (char*)"-l",
        //    (char*)"-a",
        //    (char*)"-i",
        //    NULL
        //};
        
        char* const argv_[] = {
            (char*)"top",
            NULL 
        };

       //execv("/usr/bin/ls", argv_);

       execv("/usr/bin/top", argv_);   
    }

    //一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if(ret == id)
    {
        sleep(2);
        printf("进程等待成功!\n");
    }

    return 0;
}

程序替换不仅可以替换成指令,还可以替换成我们自己写的可执行程序。

  • 用exec系列,这种系统级的函数,可以把任何语言耦合到一起。
  • 任何程序都可以用系统级接口调用其他语言的。
  • 所以说操作系统是所有技术的基座。

2.3 execlp函数:

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

file:

  • 你想执行什么程序。 —— 找到它
  • 执行指令的时候,默认的搜索路径,在哪里搜索呢?—— 环境变量PATH
  • 命名带p的,可以不带路径,只说出你要执行哪一个程序即可!

arg:

  • 想如何执行它

代码演示:

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

//有时候不想让父进程做一件事,只想让子进程做一件事
//将进程创建引入进来

int main()
{
    printf("我是父进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        //我们要子进程执行全新的程序,以前我们是子进程执行父进程的代码片段
        
        printf("我是子进程,我的pid是:%d\n", getpid());

        execlp("ls", "ls", "-a", "-l", "-i", NULL);//这里出现了两个ls,含义一样吗?-- 不一样!
        //第一个参数是供系统去找要执行谁的指令,后面一坨是表示如何执行该指令

        exit(100); //只要执行了exit,就意味着,execl系列的函数失败了 -- 进程替换失败了
    }

    //一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if(ret == id)
    {
        sleep(2);
        printf("wait success, ret : %d, 我所等待子进程的退出码: %d, 退出信号是: %d\n", ret, (status >> 8) & 0xFF, status & 0x7F);
    }

    return 0;
}

作用和execI和execv是一样的,也是执行一个新的程序。

2.4 execvp函数:

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

file:

  • PATH找,只要程序名即可。

argv[]:

  • 如何执行,将命令行参数字符串,统一放入数组中即可完成调用!

【Linux】进程控制 — 进程程序替换 + 实现简易shell

2.5 execle函数:

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

envp[]:

  • 环境变量

execle:test.c程序替换代码演示:

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

int main()
{
    //环境变量的指针声明
    extern char** environ;

    printf("我是父进程,我的pid是:%d\n", getpid());
    pid_t id = fork();
    if(id == 0)
    {
        //子进程
        //我们要子进程执行全新的程序,以前我们是子进程执行父进程的代码片段
        
        printf("我是子进程,我的pid是:%d\n", getpid());

        //绝对路径
        //execl("/home/Zh_Ser/linux/lesson16/mycmd", "mycmd", NULL);
        
        //相对路径
        //execl("./mycmd", "mycmd", NULL);
        
        //我们来手动导入一个环境变量
        char* const env_[] = {
            (char*)"MYPATH=You Can See Me!!",
            NULL 
        };

        //e: 添加环境变量给目标进程,是覆盖式的!
        //execle("./mycmd", "mycmd", NULL, env_);
        
        //execle("/usr/bin/ls", "ls", NULL, env_);

        execle("./mycmd", "mycmd", NULL, environ);

        exit(100); //只要执行了exit,就意味着,execl系列的函数失败了 -- 进程替换失败了
    }

    //一定是父进程
    int status = 0;
    int ret = waitpid(id, &status, 0);
    if(ret == id)
    {
        sleep(2);
        printf("进程等待成功!\n");
    }

    return 0;
}

上述代码代码在程序替换的时候,执行了./mycmd,目的是手动导入环境变量的时候,执行./mycmd获取导入的环境变量。

mycmd.cpp代码演示:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

using namespace std;

int main()
{
    extern char** environ;

    cout << "打印环境变量" << endl;
    for (int i = 0; environ[i]; i++)
    {
        printf("%d: %s\n", i, environ[i]);
    }

    cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    //根据环境变量名,获取环境变量的内容
    cout << "PATH:" << getenv("PATH") << endl;
    cout << "----------------------------------------------" << endl;
    cout << "MYPATH:" << getenv("MYPATH") << endl;
    cout << "----------------------------------------------" << endl;
    
    //程序崩溃了 -- 因为环境变量里根本就没有MYPATH  
    
    cout << "Hello World!" << endl;
    cout << "Hello World!" << endl;
    cout << "Hello World!" << endl;
    cout << "Hello World!" << endl;

    return 0;
}

mycmd是为了获取环境变量。

如果我们用这种方式导入环境变量:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
出现的情况:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
将mycmd.cpp中的getenv(“PATH”)给屏蔽掉,再执行test结果就可以将MYPATH打印出来:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
e: 添加环境变量给目标进程,是覆盖式的!所以环境变量只剩下MYPATHT。

子进程会继承父进程的环境变量的!!(重点)

  • 子进程会继承父进程的环境变量,当父进程调用fork()创建子进程时,子进程会继承父进程的所有环境变量
  • 当子进程调用execlp()等函数执行其他程序时,子进程也会继承父进程的环境变量。
  • 如果需要在子进程中更改环境变量,可以使用setenv()或putenv()等函数进行更改。
  • 但是,更改的环境变量只会影响当前进程和它的子进程,并不会影响父进程或其他进程的环境变量。

如何理解覆盖?(重点)

  • 当子进程调用execle()函数替换自己的程序时,可以传递一个新的环境变量数组,以覆盖子进程继承的父进程的环境变量。如果不传递新的环境变量数组,子进程会继承父进程的环境变量。因此,如果在调用execle()函数时没有传递新的环境变量数组,子进程的环境变量不会被覆盖。
  • 如果传递了新的环境变量数组,则子进程的环境变量将被替换为新的环境变量数组中的值。这可能会导致子进程无法访问父进程中的一些环境变量,除非在新的环境变量数组中显式地包含它们。

验证execle覆盖了子进程会继承父进程的环境变量:

  • 我们执行test程序的时候
  • 调用execle接口,程序替换去执行mytest
  • 既然mytest是替换了子进程,它就会继承父进程的全部环境变量
  • execle函数我们传了一个env_将子进程的环境变量覆盖了

【Linux】进程控制 — 进程程序替换 + 实现简易shell
我们在mycmd程序开始的地方,加了查看全部环境变量的代码:

extern char** environ;

for (int i = 0; environ[i]; i++)
{
	printf("%d: %s\n", i, environ[i]);
}

目的是通过该代码查看子进程(mycmd)的环境变量,被execle传的env_覆盖之后的样子:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
显而易见,子进程的环境变量只有env_[]的内容了!!!所以getenv("PATH")才获取不到!!!

正确做法:

我们将全部环境变量传过去,将environ传过去。

【Linux】进程控制 — 进程程序替换 + 实现简易shell


补充:(重点)

  • ls 是一个常见的系统命令,它通常位于系统的某个标准路径(如 /bin 或 /usr/bin)。即使 PATH 为空,execlp() 会检查这些标准路径,找到 ls 的可执行文件并执行它。
  • 可能是直接在execlp中定义好的路径了,所以 PATH 环境变量没了也可以找到。

详细说明:

  • 如果PATH环境变量为空,execlp()函数会无法在环境变量中查找可执行文件的路径。但是,execlp()函数会检查一些默认路径,例如/bin、/usr/bin等,来查找可执行文件。因此,即使PATH为空execlp()函数也可能会在这些默认路径中找到可执行文件并执行它
  • 但是,如果在默认路径中也找不到可执行文件,则execlp()函数会执行失败,并将errno设置为ENOENT,表示无法找到可执行文件。因此,如果需要执行特定路径下的可执行文件,最好使用execv()或execve()等函数,并指定可执行文件的完整路径。这样可以避免依赖PATH环境变量来查找可执行文件的路径。

验证:

  • 我们在在mycmd程序中再进行程序替换
  • 用execlp函数第一个参数是在PATH路径下找的可执行文件
  • mycmd进程的环境变量中只有一句话(只有MYPATH了)
  • 但是我们照样可以在mycmd中进行程序替换执行出ls的结果!!

【Linux】进程控制 — 进程程序替换 + 实现简易shell
即使我们将父进程中的PATH给改了,命令行中都用不了ls,execlp照样可以找到ls并执行它。

【Linux】进程控制 — 进程程序替换 + 实现简易shell

2.6 execvpe函数:

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

有了上面的基础这个想必就不用再啰嗦了,只是第二个参数传的不同,这里传的是一个指针数组。

【Linux】进程控制 — 进程程序替换 + 实现简易shell
这些函数原型看起来很容易混,但只要掌握了规律:

  • l (list) : 表示参数采用列表
  • v (vector) : 参数用数组
  • p (path) : 有p自动搜索环境变量PATH
  • e (env) : 表示自己维护环境变量

为什么有那么多的接口?

  • 目的是:适配应用场景
  • 其实上述函数都是对系统接口的封装

严格意义来说不是系统接口,是基于系统接口之上的封装。

真正意义上的系统接口:

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

上述6个函数在执行时都会调用execve()函数,将参数列表和环境变量数组转换为execve()函数所需的格式,并调用execve()函数来执行可执行文件。因此,execve()函数是这些函数的底层实现。


3. 实现简易版shell

只要我们懂得了程序替换的原理,会用程序替换的接口,就很好理解:

  • shell本身执行起来就是个死循环
  • 我们命令行就是去执行其他程序
  • shell创建子进程,将子进程给替换掉就ok了
  • 过程中要获取输入指令等操作…

myshell代码实现:

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

#define SEP " "
#define NUM 1024
#define SIZE 128

char command_line[NUM];
char* command_args[SIZE];

char env_buffer[NUM];

extern char** environ;

//对应上层的内建命令
int ChangeDir(const char* new_path)
{
    chdir(new_path);

    return 0;//调用成功
}

void PutEnvInMyShell(char* new_env)
{
    putenv(new_env);
}

int main()
{
    //shell本质就是一个死循环
    
    while(1)
    {
        //不关心获取这些属性的接口,搜索一下都有
        
        //1.显示提示符
        printf("[用户名@我的主机名 当前目录]# ");
        fflush(stdout);

        //2.获取用户输入
        memset(command_line, '\0', sizeof(command_line));

        //从键盘获取,标准输入,stdin,获取到的是C风格的字符串(stdio.h结尾的),'\0'结尾
        fgets(command_line, NUM, stdin);
        command_line[strlen(command_line) - 1] = '\0';//清空\n回车
        //printf("%s\n", command_line);

        //3. "ls -a -l -i" -> "ls" "-a" "-l" "-i" 字符串切分 -- 因为这些参数一定得以列表或者数组方式传递给程序替换接口
        //shell必须切分,因为必须调用execl函数
        
        //将第一个字符串地址用0号下标指向,第二个字符串地址用1号下标指向 
        command_args[0] = strtok(command_line, SEP);

        int index = 1;

        //给ls命令添加颜色: 如果提取出来的程序名是ls -- 1下标设置成改颜色的
        if(strcmp(command_args[0], "ls") == 0) command_args[index++] = (char*)"--color=auto";

        //strtok截取成功返回字符串起始地址
        //截取失败,返回NULL
        while(command_args[index++] = strtok(NULL, SEP));
        
        //for debug
        //int i = 0;
        //for(i = 0; i < index; i++)
        //{
        //    printf("%d : %s\n", i, command_args[i]);
        //}
        
        //4.TODO -- 编写后面的逻辑,内建命令(由父Shell自己实现的自己调用的一个函数)
        if(strcmp(command_args[0], "cd") == 0 && command_args[1] != NULL)
        {
            //让调用方进行路径切换,父进程
            ChangeDir(command_args[1]);
            continue;
        }
        
        //走到这里一定是将命令行参数解析完了,包括命令 + 选项
        
        //将环境变量的信息导入在了父进程的上下文当中
        if(strcmp(command_args[0], "export") == 0 && command_args[1] != NULL)
        {
            //环境变量列表(是个指针数组,每个元素是个指针指向一个环境变量)
            //我们传的是一个字符串首地址,但是环境变量的内容还是我们自己维护的
            //目前,环境变量信息在comman_line,会被清空,那么环境变量当然就没有了
            //所以此处我们需要自己保存一下环境变量的内容
            
            strcpy(env_buffer, command_args[1]);
            PutEnvInMyShell(env_buffer);
            //PutEnvInMyShell(command_args[1]);//MYENV=112233
            continue;
        }

        //5.创建进程,执行
        //如果自己直接程序替换的话,就把自己写的shell给替换了
        
        pid_t id = fork();
        if(id == 0)
        {
            //子进程
            //6.程序替换
           
            //execvpe(command_args[0], command_args, environ);
            execvp(command_args[0], command_args);

            exit(1);//执行到这里,子进程一定替换失败了
        }

        int status = 0;
        
        pid_t ret = waitpid(id, &status, 0);

        if(ret > 0)
        {
            printf("等待子进程成功: sig: %d, code: %d\n", status & 0x007F, (status & 0xFF00) >> 8);
        }

    }//end while

    return 0;
}

ls设置颜色的办法:
【Linux】进程控制 — 进程程序替换 + 实现简易shell

3.1 内建命令等问题的解决:

3.1 - 1 cd命令的处理:

在命令行中操作cd时,会跳转路径,但是用绝对命令时,就不行了,还是原来的路径:

  • 一个进程也存在对应路径, 进程对应的路径可以理解成
  • 当进程启动的时候时,在哪个路径启动时,这个进程所在路径就是当前进程所启动的路径

一般一个进程的路径是会被于进程继承的,路径的变化我们希望的是父进程路径的变化。

【Linux】进程控制 — 进程程序替换 + 实现简易shell
原因就是,我们平时用的cd时做过处理的cd:

  • 我们知道指令都是一些可执行程序
  • 执行可执行程序就是去执行其他程序,程序替换了
  • 如果我们创建的子进程跳转路径
  • 子进程退出之后,只是子进程的路径跳转了
  • 并不影响父进程的路径,会发现命令行路径还是没变
  • 显然这这种做法是不可取的

就不能用程序替换的方式来执行一些特殊的命令了:

  • 我们可以在父进程将一些命令单独处理
  • 让其不进行程序替换

重点:

  • 程序替换影响的是子进程和父进程没关系,子进程一 跑就完了,曾经所有的操作就没有意义,路径切换就没意义了,所以我们要让父进程的路径发生变化。
  • 如果有些行为,是必须让父进程shell执行的,不想让子进程执行,绝对不能创建子进程!只能是父进程自己实现对应的代码!

内建命令:

  • 我们把由父进程自己提供的代码或者提供的逻辑(在命令行上体现的也是一个命令),但是这部分命令不是子进程执行的,而是父进程自己执行的,我们叫做内建命令。
  • 由shell自己执行的命令,我们称之为内建(内置bind- in)命令。

更改工作目录的函数:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
验证一下:
【Linux】进程控制 — 进程程序替换 + 实现简易shell

3.2 - 2 export的处理:

导入环境变量:

【Linux】进程控制 — 进程程序替换 + 实现简易shell
export不是一个可执行程序和cd,ls,cat等指令不同:

export是一个shell内置命令,用于设置环境变量。它并不是一个可执行程序,而是由shell解释器直接执行的命令。当我们在shell中使用export命令时,它会将指定的环境变量设置为当前shell进程的环境变量,以便后续的命令或程序可以使用该环境变量。

所以用execvp进行程序替换的时候,是不能替换成功的!

【Linux】进程控制 — 进程程序替换 + 实现简易shell
注意:

  • 环境变量列表(是个指针数组,每个元素是个指针指向一个环境变量)
  • 我们传的是一个字符串首地址,但是环境变量的内容还是我们自己维护的
  • 目前,环境变量信息在comman_line,会被清空(环境变量要一直维护),那么环境变量当然就没有了
  • 所以此处我们需要自己保存一下环境变量的内容

环境变量是数据,进程替换不是替换进程的代码和数据吗?

  • 但是环境变量是属于系统的数据
  • 子进程在执行程序替换时
  • 当前进程的环境变量数据,不会被替换掉
  • 而且是以父进程为模版继承下来的
  • 所以才会让父进程以内建命令的方式putenv,子进程就能直接获取了

环境变量的数据,在进程的上下文中:文章来源地址https://www.toymoban.com/news/detail-463746.html

  1. 环境变量会被子进程继承下去,所以他会有全局属性。
  2. 当我们进行程序替换的时候,当前进程的环境变量非但不会被替换,而且是继承父进程的!!

到了这里,关于【Linux】进程控制 — 进程程序替换 + 实现简易shell的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux】Linux进程控制 --- 进程创建、终止、等待、替换、shell派生子进程的理解…

    柴犬: 你好啊,屏幕前的大帅哥or大美女,和我一起享受美好的今天叭😃😃😃 1. 在调用fork函数之后, 当执行的程序代码转移到内核中的fork代码后 ,内核需要分配 新的内存块 和 内核数据结构 给子进程, 内核数据结构包括PCB、mm_struct和页表,然后构建起映射关系 ,同时

    2024年01月16日
    浏览(24)
  • Linux进程控制【进程程序替换】

    ✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Good judgment comes from experience, and a lot of that comes from bad judgment. 好的判断力来自经验,其中很多来自糟糕的判断力。 子进程 在被创建后,共享的是 父进程 的代码

    2024年01月17日
    浏览(18)
  • [Linux 进程控制(二)] 进程程序替换

    首先,我们要认识到,我们之前fork()所创建的子进程,执行的代码,都是父进程的一部分(用if-else分流或者执行同样的代码)! 如果我们想让子进程执行新的程序呢? 执行全新的代码和访问全新的数据,不再和父进程有瓜葛,这种技术就叫做程序替换 ,下面我们就来学习一

    2024年03月14日
    浏览(25)
  • 【Linux初阶】进程替换的应用 - 简易命令行解释器的实现

    🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:使用代码手段实现一个简易的命令行解释器,其中功能包括:打印输出提示符、获取用户输入、字符串切割、执行命令、ls指令下拥有颜色提示、cd、echo; 🚢🚢作者简介:计算机海洋的

    2024年02月07日
    浏览(15)
  • Linux--进程控制(2)--进程的程序替换(夺舍)

    目录 进程的程序替换 0.相关函数 1.先看现象  2.解释原理 3.将代码改成多进程版  4.使用其它的替换函数,并且认识函数参数的含义 5.其它  关于进程替换我们需要了解的6个函数: 函数解释: 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。 如果调用出

    2024年04月29日
    浏览(6)
  • 【Linux】Linux进程控制及程序替换

    🍎 作者: 阿润菜菜 📖 专栏: Linux系统编程 在linux中fork是一个很重要的函数,它可以已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 fork函数返回两个值,一个是子进程的进程号(pid),另一个是0。 父进程可以通过pid来区分自己和子进程,子进程可

    2024年02月02日
    浏览(14)
  • 【linux】进程替换的应用|shell解释器的实现

    当我们学过了进程替换之后,本篇文章可以根据进程替换的知识带你自主实现一个shell命令行 实现步骤 1.显示命令行提示 2.读取输入指令以及对应选项 3.分割第二步的指令以及选项到命令行参数表中 4.处理内建命令 5.进程替换 我们通过观察bash的命令行提示发现他是由三部分

    2024年04月26日
    浏览(9)
  • 『Linux从入门到精通』第 ⑱ 期 - 学会了程序替换,我决定手写一个简易版shell玩一玩...

    🌸作者简介: 花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。 🌸 专栏简介:本文收录于 Linux从入门到精通 ,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

    2024年02月14日
    浏览(14)
  • 【探索Linux】—— 强大的命令行工具 P.10(进程的控制——创建、终止、等待、程序替换)

    前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的一些知识,也学习了一些Linux的基本操作,也了解并学习了有关Linux开发工具vim 、gcc/g++ 使用、yum工具以及git 命令行提交代码也相信大家都掌握的不错,上一篇文章我们了解了关于进程的地址空间,今

    2024年02月08日
    浏览(16)
  • [Linux]进程控制精讲,简单实现一个shell

    目录 前言 进程创建 fork函数初识 写时拷贝 fork常见用法 fork调用失败的原因 进程终止 进程退出场景 进程退出码 查看进程退出码 退出码的含义 进程常见退出方法 exit VS _exit exit函数 _exit函数 二者的区别 return退出 进程等待 进程等待必要性 进程等待的方法 wait方法 waitpid方法

    2023年04月26日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包