ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【进程】-8-命令行参数和环境变量

【进程】-8-命令行参数和环境变量 ** 博主名称**迷途之人不知返 个人专栏: 《C语言》、《数据结构》、《C》、《Linux》️ Gitee仓库: 《C语言》、《数据结构》、《C》、《Linux》/ 算法专栏: 《算法精选集》命令行参数和环境变量1、命令行参数1.1、main函数可以包含参数吗1.2、字符串的内容是什么1.3、命令行参数2、环境变量2.1、见见windows下的环境变量(PATH)然后引出概念2.2、Linux下的环境变量2.2.1、PATH2.2.1.1、为什么不能直接执行自制程序——PATH的作用2.2.1.2、如何添加2.2.3、Linux其它环境变量2.3、获取环境变量2.4、理解环境变量的产生2.4.1、子进程的环境变量表2.4.2、bash的环境变量表2.4.3、两个细节命令行参数和环境变量算是操作系统比较冷门的知识点。但是学完之后我们会对进程的执行有进一步认识所以值得一学。1、命令行参数我们以一个有意思的现象做引子1.1、main函数可以包含参数吗我们以前写过的大部分main函数都是不带参数的。实际上main函数与一些普通的函数一样也是可以包含参数的intmain(intargc,char*argv[]){// ...}其中argv指针数组。argv实际上有(argc 1)个char*元素最后一个位置赋值NULL。argc指针数组中的有效数组元素。这时我们就会有一个疑问既然argv是一个指针数组那么argv存的一个个指针指向字符串的内容是什么呢1.2、字符串的内容是什么实验一// test1.c#includestdio.hintmain(intargc,char*argv[]){printf(argv[%d]: %s\n,0,argv[0]);return0;}执行./test.exe结果实验一结果我们执行的./test.exe被放到了argv指针数组中。(实际上是./test.exe字符串的首地址被放入了argv的0下标位置上)实验二// test2.c#includestdio.hintmain(intargc,char*argv[]){inti0;for(;argv[i];i)printf(argv[%d]: %s\n,i,argv[i]);return0;}执行./test.exe abcd 1234结果实验二结果输入的字符串指令以空格为分界依次放入argv指针数组中。根据实验二我们就又可以做一个有趣的实验// test3.c#includestdio.hintmain(intargc,char*argv[]){if(argc1)// 一定要这步判断不然只输入./test.exe的话只放入了./test.exeargv[1]就是NULL导致引用空指针{if(strcmp(argv[1],-a)0)printf(执行功能一。\n);elseif(strcmp(argv[1],-b)0)printf(执行功能二。\n);elseprintf(执行默认功能。\n);}else{printf(执行默认功能。\n);}return0;}观察多次执行的结果这与我们之前使用ls指令的时候添加-a, -l等多选项就以不同方式展示文件信息的现象是非常类似的所以argv存储的字符串就是我们在命令行输入的命令字符串以空格为分界的一个个子串。像这样在命令行输入的字符串参数我们称之为命令行参数。1.3、命令行参数我们在命令行输入以空格为分隔的多个字符串子串起始地址填入argv表表最后以NULL结尾。然后argc与argv表会传递给main函数使得main函数能够实现多选项的功能例如指令多选项的功能。而我们输入的以空格为分隔的多个字符串就是命令行参数。对于命令行参数还有三个细节解析命令行参数这项工作通常是由bash进程做的bash解析好了argc与argv表如何传递到main函数中呢目前我们只需知道操作系统是通过程序替换完成传递工作的就行了argv表可以是空的也就是说main函数也可以不包含命令行参数这就是我们之前一直在写的无参的main函数。2、环境变量对于变量我们知道变量 变量名 变量内容对于一般的变量变量内容可能是数值、字符串、十六进值地址……而对于环境变量变量内容就是和系统相关的内容。2.1、见见windows下的环境变量(PATH)然后引出概念windows系统下有一个环境变量PATH这个环境变量有什么用呢我们打开命令行窗口比如说我们想打开QQ音乐而QQ音乐本质上是一个可执行程序我们想直接在windows命令行窗口用指令QQMusic.exe打开QQ音乐是行不通的。因为当前操作系统不知道QQMusic.exe到底在哪个路径下这时我们设置环境变量PATH其实就是把QQMusic.exe的所处路径加入到PATH内部(建议添加完路径后再刷新一下命令行窗口)我们再回到命令行窗口执行QQMusic.exeQQ音乐客户端就被我们打开了类似的我们再windows下安装git, python, java等工具软件时这些工具软件都会要求我们配置环境变量PATH。当我们配置好后我们就可以在系统的任意位置执行命令调用工具。意味着环境变量可以让我们随时随地使用软件工具。像PATH这样用来做记录工作路径、记录系统版本信息等做系统级任务的变量就是环境变量。环境变量是系统级变量保存着系统启动和运行的核心参数。由于我们可以在任意位置使用配置过PATH的软件工具所以包括PATH在内的环境变量一般具有全局性(即全局变量)。2.2、Linux下的环境变量这一部分我们将介绍几个常见的环境变量及其相关的环境变量命令。2.2.1、PATHLinux下也有环境变量PATH执行指令echo $PATH我们就能查看当前PATH记录的所有路径。2.2.1.1、为什么不能直接执行自制程序——PATH的作用相信同学们之前肯定有这样一个疑问为什么我们使用ls, pwd等命令时不用指明所处路径而执行自制程序(如test.exe, myproc.exe)的时候必须./指明程序在当前路径下答案就在于PATH。系统启动后会维护一个环境变量PATHPATH里面记录的是系统常用软件的所处路径。当用户想要执行一个路径不明确的程序bash就会遍历PATH中的所有路径以寻找指定程序。像ls, make, pwd等指令一般处在/usr/bin路径下而/usr/bin确实被记录在PATH之中所以直接调用时bash遍历PATH就能找到并执行。像用户自制的test.exe, myproc.exe等程序由于所处路径并未记录在PATH中bash遍历完了PATH也没有找到于是执行失败。这就需要我们手动指明程序所处路径。如果我们硬是要直接执行自制指令可以有以下两种方法将程序拷贝一份到PATH保存的工作路径下添加当前路径到PATH。2.2.1.2、如何添加难道是PATH/[当前路径]吗我们发现myproc.exe确实可以直接执行了但是有些常用的命令却用不了了。实际上执行PATH/[当前路径]是一个覆盖操作意味着这么修改后PATH里面只有当前路径了而我们退出XShell重新登录一次PATH又恢复原样了。我们就可以得出结论命令行中修改环境变量是内存级修改重新登录账号后会恢复。我们的预期是“添加”而不是“覆盖”所以我们应该这样做PATH$PATH:[新路径]小贴士1我们曾经见过which命令。之所以which命令能够查到任意程序所在的位置是因为which通过遍历PATH来寻找目标程序的所在路径。2.2.3、Linux其它环境变量HOME执行echo $HOME环境变量HOME保存的内容是家目录。PWD环境变量PWD保存的内容是当前路径。PWD会随着用户切换路径而不断更新保存内容(就是最新的当前路径)。HISTSIZEhistory默认只会保存前1000个曾经执行的指令是因为环境变量HISTSIZE默认是1000。OLDPWDOLDPWD记录当前路径的上一个路径。所以我们就能明白执行cd -的时候为什么会回退到上一个路径以及重复cd -会在当前路径与上一个路径来回切换因为OLDPWD保存了上一个路径的信息。查看环境变量的方法执行env我们就能看到所有环境变量2.3、获取环境变量环境变量还是很有用的。那么我们如何获取环境变量呢命令行参数法(env表方法)其实main函数还可以包含一个参数intmain(intargc,char*argv[],char*env[]){}env和argv一样也是一个指针数组。而env中存的每一个指针指向的都是环境变量。// test4.c#includestdio.hintmain(intargc,char*argv[],char*env[]){inti0;for(;argv[i];i)printf(argv[%d]: %s\n,i,argv[i]);for(i0;env[i];i)printf(env[%d]: %s\n,i,env[i]);return0;}第三方全局变量environ法environ其实是一个二级指针(char**)指向的就是数组指针env表。我们可以通过environ查看所有的环境变量// test5.c#includestdio.hintmain(intargc,char*argv[],char*env[]){externchar**environ;// 要加上这句声明inti0;for(;environ[i];i)printf(env[%d]: %s\n,i,env[i]);return0;}但是上面的两个方法充其量只能做打印之用有没有一种方法能够获取环境变量的变量值函数方法getenv()getenv()输入环境变量名对于返回值如果环境变量存在返回变量值如果不存在返回(null)。所以我们就能设计一个有趣的程序只能让用户自己执行的程序。// test7.c#includestdio.h#includestdlib.h#includestring.hintmain(){char*whogetenv(USER);if(strcmp(who,yzc)0)printf(程序执行。\n);elseprintf(程序不予执行。当前用户: %s\n,who);return0;}2.4、理解环境变量的产生任何进程启动都会存在这两张表命令行参数表(argv)环境变量表(env)我们知道用户键入指令bash就会解析指令内容然后制作命令行参数表通过程序替换的方式将表传递给main函数。所以本质上bash内部的命令行参数表是用户提供的未来bash之后的子进程将通过写时拷贝的方式与bash父进程共用命令行参数表。命令行参数表一般不改变所以就不拷贝父进程bash与所有子代进程共用一张命令行参数表。那环境变量表又是怎么来的呢2.4.1、子进程的环境变量表与子进程命令行参数表的由来一样子进程环境变量表是“继承”自父进程的方式是写时拷贝。这里我们可以补充export指令即添加新的环境变量的指令。这时我们导出变量OK到bash的环境变量表中bash之后的子代进程就都能访问了。小贴士2我们上面讲了“导出变量OK”。“导出”有什么说法实际上Linux的Bash是一门解释性编程语言。我们可以在命令行中定义没有类型的变量然后用$提取变量内容此时的haha就是本地变量。本地变量只能在当前终端的bash内部使用。要想子进程也能访问我们就需要导出到环境变量表中本地变量的作用之一是支持bash内部的语法比如循环打印语句使用set指令可以显示本地变量与环境变量。2.4.2、bash的环境变量表bash的环境变量表是从系统的特定配置文件里获取而来的。我们知道每一次登录操作系统都会为我们提供命令行输入服务也就是创建当前终端下的bash进程。我们看看用户家目录下的详细信息家目录下有这两个文件.bashrc .profile我们看看.profile文件内部再看看.bashrc内部实际上用户登录系统系统创建bash进程后bash会去/home/yzc/.profile文件及其它配置文件中寻找环境变量进而制作环境变量表传递给main函数。我们可以做一个实验来验证这一点修改.profile文件。重新登录。查看环境变量与本地变量所以bash的环境变量从何而来bash扫描.profile及相关配置文件而来。2.4.3、两个细节windows下PATH窗口回到我们之前为了在windows的命令行窗口打开QQ音乐而做的修改这里增加、修改路径本质上是什么呢是修改配置文件。与Linux的export做的内存级修改比较export的修改会随着系统的退出而恢复而配置文件的修改会一直保留不会随着系统的退出而消失。内建命令不知道大家在上面的学习中有没有发现两个奇怪的现象PATH被直接复写后有些常用指令(比如cd)还能用而这些常用指令所在路径是没有保存在复写后的PATH中的为什么export能够将本地变量导出到bash的环境变量表中。那么export怎么能够影响bash这个父进程呢export难道不是子进程吗实际上相对于bash通过“创建子进程”方式执行的命令Linux还包含一种命令——内建命令。内建命令不会通过创建子进程的方式执行而是由bash亲自执行比如export env cd。我们可以认为内建命令就是bash自己内部的“函数”。当用户在命令行输入一串指令时bash就会判断这条指令是普通指令还是内建指令如果是内建指令那么bash直接执行如果不是内建指令(可能是bash里面找不到)那么bash就会遍历PATH保存的路径从而去找这条指令。
返回列表