程序替换与shell
程序替换函数execlexeclpexecvexecvpexecvpeexecle一共介绍七个函数这里全都是以exec开头的执行任何程序需要1.找到它 加载它路劲加程序名2.怎么执行例如ls,你想带什么选项呀如 -l -a -d之类由程序和选项决定l-以类似链表的形式告诉我p-不用告诉我路径我自己会到path路径下查找v-vector以数组为参数传递e-envexecl第一个参数是path-你要执行谁(给路径)… -可变参数(你想怎么执行)典型代表printf(上篇文章已经简单介绍过)必须以NULL结尾-告诉选项是结尾了判断递归结束的条件结论命令行怎么写你就怎么填execl(/usr/bin/ls,ls,-a,-l,NULL);//路径程序名选项后面跟着NULLexeclp和execl最重大的区别第一个参数后面参数你想怎么执行一样execlp第一个参数是file只要告诉我程序名execlp会自动到环境变量PATH所标明的路径下查找不了解可以到我之前写的环境变量与虚拟地址空间查看execlp(ls,ls,-a,-l,NULL);//查找目标告诉系统“我要找叫 ls 的程序”,要执行ls指令选项后面跟着NULL虽然省略第二个ls可以省略但不建议省略execv第一个参数和execl一样要路径execv没有可变参数而是变成了指针数组把参数构建成一个数组来传递参数//const char* 是内容不可变而 char* const 是指针本身不可变char*argv[]{ls,-a,-l,NULL};//不带const算是权限缩小是可以的但会提示//注ls,-a,-l在编译器中类型是const char*你这样写编译器会给提示如果想消除这个提示有两种方法//1.将数组类型改为const char*//2.强制类型转化char* argv[] { (char*)ls, (char*)-a, (char*)-l, NULL };虽然编译通过了但如果你后续在代码中真的去修改这些字符串比如 argv[0][0] L;程序会直接崩溃Segmentation Fault因为 ls 实际上还是存储在只读内存区的。char*argv[]{(char*)ls,(char*)-a,(char*)-l,NULL}//写成上述形式execv(/usr/bin/ls,argv);看着这个argv有没有一点眼熟呢没错这样就可以解释通了ls里面有自己的main函数main函数里面的argv接受的就是你的execv里面的argv,再通过遍历你的argv得到argc,之前写的main函数是bash给我们传递进来的bash会构建出这个表用程序替换传递你自己的程序。execvpv-vectorp-pathchar*argv[]{(char*)ls,(char*)-a,(char*)-l,NULL}execvp(argv[0],argv);//argv[0]是ls,ls就是程序名//写习惯一点可以写成execvp(ls,argv);总结l(list)表示参数采用列表v(vector)表示参数用数组p(path)有p自动搜索环境变量pathl和v二选一不会同时存在e(env)表示自己维护环境变量上面的程序替换函数能不能替换我们自己写的自己的程序呢可以的下面举个例子假设当前目录下有这么一个code.c好现在我在这个目录下创建一个myexe.c内容如下好我现在想在code.c下执行这个文件需要先将这个myexe.c先编译成myexe,因为exec函数只识别可执行文件不能识别.源代码文件好前期准备工作已经执行完了现在就可以着手于code.c文件了这里讲一下execl第一个一九是要把路径写出来因为myexe和code.c在同一个目录下用相对路径即可第二个是文件名就是myexe后面不用带选项了直接连接一个NULL表示结束即可我们发现myexe的执行结果出现在了code.c的子进程里面说明替换成功了不止可以替换操作系统里面的函数我自己写的可执行文件也是可以替换的。当然这里用的c编译好的程序替换用java编译好的也可以程序替换自己替换自己也可以不过不推荐容易死循环java语言因为没学这里就不展示了三个月之内把这段空缺的java语言的程序替换补上以及会讲解一下java语言的语法及其知识点vs2022这个IDE可以看成我写好了代码.c文件MSVC 编译器编译链接最后VS2022 调试器 可以让你调试所以现在就可以理解vscode配置环境到底是什么了就是三个部分1.下载“写代码的地方” —— VSCode文本编辑器作用它就像一个高级记事本负责让你舒服地写字写代码提供高亮、自动补全等功能。2.下载“编译器” —— 编译器工具链类似gcc gMSVC3.配置环境变量与插件光下载了还不行你得做两件事让它们连起来配置环境变量告诉系统编译器在哪安装插件告诉 VSCode 怎么调用编译器所以刚开始入门的话都不会建议新生自己去vscode配置环境而是去集成开发环境IDE去练习写代码。execvpeintexecvpe(constchar*file,char*constargv[],char*constenvp[]);//p表示会到环境变量里面找文件不用传递路径v表示以数组的形式传递e是envp,传入全新的环境变量路径的两种选择在 execvpe(const char *file, char *const argv[], char *const envp[]) 中第一个参数 file 有两种用法绝对路径或相对路径如果你传入的是类似 /bin/ls 或 ./my_program 这样的路径系统会直接执行该路径下的可执行文件。它不会去搜索 PATH 环境变量。例子execvpe(“/usr/bin/gcc”, argv, envp);仅文件名需要配合 PATH如果你传入的只是文件名例如 ls那么 execvp 或 execvpe 会根据你当前环境中的 PATH 环境变量去各个目录下一一查找找到后执行。这里的path,是第三个参数中的path,不是父进程的path下面是之前写的代码是命令行参数写过的代码#incluediostreamintmain(int argc,char*argv[],char*env[]){int i0;for(;iargc;i){printf(argv[%d]-%s\n,i,argv[i]);}int j0;for(;env[j];j){printf(:env[%d]:%s\n,j,env[j]);//env[i]最后一个也是NULL}return0;}假设这个代码是卸载code.c里面的他便便宜之后形成了code可执行文件char*myargv[]{(char*)code,(char*)-a,(char*)-b,NULL};extern char**environ;//是为了告诉编译器“这个变量不是我在当前文件里定义的它存在于系统的标准库libc中请去那里找它。”execvpe(code,myargv,environ);exit(3);子进程的参数是父进程通过程序替换函数传递给子进程的给execvpe这个函数传递全新的环境变量调用程序替换时可以传递enviorn,也可以自定义myenv如果你是使用myenv的话子进程的环境变量将会遵循你给的env而不是和父进程一样如果你在调用 execvpe或 execve时显式地将第三个参数设置为全局变量 environ那么新进程的环境变量在逻辑上就和父进程完全一样。默认环境变量execvpe(“./code”,myargv,myenv);覆盖式的使用全新的环境变量execvpe(“./code”,myargv,environ);使用父进程的环境变量如果是想老的环境变脸和在加上自己定义环境变量如果我想在传递环境变量的时候在原有的环境变量上给子进程添加环境变量呢int putenv(char *string);将这个字符串添加到环境变量中代码样例#includestdlib.h#includeunistd.hintmain(){// 使用 putenv 修改当前进程的环境变量// 注意这里的字符串最好是静态存储区或通过 malloc 分配的putenv(MY_NEW_VARhello_world);// 现在调用 execvp (此时它会继承刚才 putenv 修改后的环境)char*argv[]{./child_program,NULL};execvp(./child_program,argv);return0;}当然这样写父进程也会被修改但没什么问题毕竟exec之后代码就被覆盖了如果实在不想让父进程进行修改可以#includestdio.h#includestdlib.h#includeunistd.h#includesys/wait.hintmain(){pid_t pidfork();if(pid0){// --- 这里是子进程 ---// 我们只在子进程里玩 putenvputenv(MY_VARchild_only);char*argv[]{/usr/bin/env,NULL};// 用 env 命令打印出来看看execvp(env,argv);}else{// --- 这里是父进程 ---wait(NULL);// 等子进程跑完printf(父进程检查 MY_VAR: %s\n,getenv(MY_VAR));// 这里会输出 (null)证明父进程没被污染}父子进程都有命令行参数和环境变量,谁调用就该用谁的环境变量证明如上结论子进程可以直接继承父进程环境变量可以自己定义新的环境变量也可以添加环境变量----------------------------------------------------------------------------------------------------------------execleintexecle(constchar*path,constchar*arg,.../* (char *) NULL, char *const envp[] */);execl,exelp,execle,execv,execvp.execvpe都是库函数execve是系统调用这里的库函数底层都是execve。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2471587.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!