网站建设众筹,wordpress不跳转页面,淘宝客网站怎样做seo,电影站的seo目录
前言
替换的原理
替换函数
记忆技巧
函数使用
execl
execlp
execv
execvp
execle
execvpe
调用其它语言的程序
模拟实现一个shell 前言
关于本文可以先去看看上一篇【Linux】进程控制详解-CSDN博客可以更好的理解这里的内容
学完本篇文章#xff0c;你就…目录
前言
替换的原理
替换函数
记忆技巧
函数使用
execl
execlp
execv
execvp
execle
execvpe
调用其它语言的程序
模拟实现一个shell 前言
关于本文可以先去看看上一篇【Linux】进程控制详解-CSDN博客可以更好的理解这里的内容
学完本篇文章你就可以自己设计一个mini版的shell解释器还可以用你写自己的代码区执行其它语言的程序。
替换的原理
用fork创建子进程后执行的是和父进程相同的代码但有可能需要执行不同的代码分支那么子进程往往要调用一种exec系列函数以执行另一个全新程序。当进程调用一种exec系列函数时该进程的用户空间代码和数据完全被新程序替换从新程序的启动例程开始执行。调用exec系列函数并不创建新进程所以调用exec系列函数前后该进程的ID并未改变。 替换函数 返回值如果调用成功则加载新的程序从启动代码开始执行不在返回调用失败则返回-1。
记忆技巧
l(list)表示参数采用列表v(vector)表示参数采用数组p(path)第一个参数path不用输入路径给出命令名即可它会在环境变量PATH当中搜索对应的命令e(env)将自己维护的环境变量传递给需要替换的进程
函数名参数格式是否带路径是否使用当前环境变量execl列表否是execlp列表是是execle列表否否需自己维护环境变量execv数组否是execvp数组是是execvpe数组否否需自己维护环境变量
函数使用
一旦发生了替换那么替换函数后面的代码就不会再执行了。
int main()
{printf(当前进程的开始代码\n);execl(/usr/bin/ls, ls, -a, -l, NULL);printf(当前进程的结束代码\n);return 0
}注在调用替换函数时末尾最好加上NULL代表结束。
虽然我们可以不用创建子进程来使用替换函数但是我们创建了子进程替换的进程就是子进程而父进程不受影响那么父进程就可以聚焦在读取数据解析数据指派进程执行代码等功能了。
execl
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.hint main()
{pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());execl(/usr/bin/ls, ls, -a, -l, NULL);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}execlp
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.hint main()
{pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());execlp(ls, ls, -a, -l, NULL);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}execv
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.h#define NUM 16int main()
{pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());char* const _argv[NUM] {(char*)ls,(char*)-a,(char*)-l,NULL };execv(/usr/bin/ls, _argv);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}execvp
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.h#define NUM 16int main()
{pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());//execl(/usr/bin/ls, ls, -a, -l, NULL);//execlp(ls, ls, -a, -l, NULL);char* const _argv[NUM] {(char*)ls,(char*)-a,(char*)-l,NULL };execvp(ls, _argv);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}execle mycmd.c
#include stdio.h
#include string.h
#include stdlib.hint main(int argc, char* argv[])
{if(argc ! 2){printf(can not execute\n);exit(1);}printf(获取环境变量:MY_VALUE:%s\n, getenv(MA_VALUE));if(strcmp(argv[1], -a) 0){printf(hello 我是a\n);}else if(strcmp(argv[1], -b) 0){printf(hello 我是b\n);}else {printf(defalut\n);}return 0;
}myproc.c
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.h#define NUM 16
const char* myfile /home/hjx/for_linuxtest/test43/mycmd;int main(int argc, char* argv[], char* env[])
{char* const _env[NUM] {(char*)MY_VALUE332335454,NULL };pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());execle(myfile, mycmd, -a, NULL, _env);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}所以mycmd.c就拿到了这里的环境变量
execvpe
和上面的类似就不再演示了 其实系统调用的接口只有一个——execve 而以上介绍的函数是操作系统是为了满足不同的调用场景提供的基本封装。 调用其它语言的程序
print(hello python)
print(hello python)
print(hello python)
print(hello python)
print(hello python)
print(hello python)#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/types.h
#include sys/wait.hint main()
{pid_t id fork();if(id 0){perror(fork);exit(2);//子进程创建失败}else if(id 0){//子进程printf(子进程开始执行,pid:%d\n, getpid());execlp(python, python, test.py, NULL);exit(1);//替换失败则终止进程}else {//父进程printf(父进程开始执行,pid:%d\n, getpid());int status;pid_t wid waitpid(-1, status, 0);//阻塞等待if(wid 0){printf(wait success, exit code:%d\n, WEXITSTATUS(status));}}return 0;
}模拟实现一个shell
有了上面的这些知识那么我们可以自己设计一个简易版的shell。
shell代码链接minishell
效果展示 今天的分享就到这里了如果内容有错的话还望指出谢谢