目录
- 一、命令行参数
- 1.1 命令行参数是什么?
- 1.2 设计命令行参数的意义
- 二、环境变量
- 2.1 环境变量的基本概念
- 2.2 常见环境变量
- 2.2.1 PATH
- 2.2.1.1 通过命令行配置PATH
- 2.2.1.2 使自己的程序像系统中指令一样运行
- 2.2.2 HOME
- 2.2.3 PWD
- 2.3 查看操作系统中所有的环境变量(env)
- 2.4 如何在进程中获取环境变量
- 2.4.1 getenv函数
- 2.4.2 命令行的第三个参数(char* env[])
- 2.4.3 全局变量environ(C语言/C++)
- 2.5 进程如何获取环境变量
- 2.5.1 .bash_profile文件
- 2.5.2 .bashrc文件
- 2.5.3 /etc/bashrc文件
- 2.6 如何向进程中设置环境变量
- 2.6.1 在命令行中设置环境变量
- 2.6.2 修改系统中的配置文件
- 2.7 本地变量 vs 环境变量
- 2.7.1 本地变量
- 2.7.2 环境变量
- 2.7.2.1 环境变量通常是具有全局属性的
- 2.8 命令常见分类
- 2.8.1 常见命令
- 2.8.2 内建命令
- 2.9 和环境变量相关的命令
- 结尾
一、命令行参数
1.1 命令行参数是什么?
在我们学习C语言的时候,没怎么使用过main函数的参数,实际上main函数是可以有参数的。int main(int argc, char *argv[])
,其中main函数中的两个参数就叫做命令行参数。
这两个参数具体有什么作用呢?接下来使用代码进行解答。
#include<stdio.h> int main(int argc , char* argv[])
{ int i = 0; for(; i < argc ; i++) { printf("%d %s\n",i,argv[i]); } return 0;
}
当使用命令行启动程序,上图即是运行程序后的结果,细心一点可以发现,将命令行上的指令看成一个长字符串,以空格为分隔符,将长字符串分为几个短字符串,参数argc就是短字符串的个数,参数argv是指针数组,用来存放分割后短字符串的地址。
在命令行上输入的指令,会被Shell或OS(操作系统)自动处理为短字符串,将短字符串的个数传给argc,并生成数组用来存放短字符串的地址,再将数组传给argv。
1.2 设计命令行参数的意义
命令行参数可以使同一个程序,通过不同的选项,实现不同的功能。
命令行参数,可以支持各种指令级别的命令行选项的设置,在以前学到的指令中,给指令带上不同的选项,就可以实现不同的功能,就是这个原理。
下面我将编写一个命令行级别的计算器代码为大家演示命令行参数应该如何使用。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main(int argc , char* argv[])
{// 这里argc必须等于4,指令需要能够拆分为四个短字符串// 第一个字符串为程序名// 第二个字符串为需要进行何种操作// 第三、四个字符串为操作数if(argc != 4){// 当字符串的个数不为4时,则说明输入错误,输出操作说明printf("Usage:%s op[add|sub|mul|div] d1 d2\n",argv[0]);// argc 必定大于0,启动程序需要输入程序名return 1; }// 将操作数从字符串转化为整形int d1 = atoi(argv[2]);int d2 = atoi(argv[3]); if(strcmp(argv[1],"-add") == 0) { // add , 将两个操作数相加 printf("%d + %d = %d\n" , d1 , d2 , d1 + d2); } else if(strcmp(argv[1],"-sub") == 0) { // sub , 将两个操作数相减 printf("%d - %d = %d\n" , d1 , d2 , d1 - d2); } else if(strcmp(argv[1],"-mul") == 0) { // mul , 将两个操作数相乘 printf("%d * %d = %d\n" , d1 , d2 , d1 * d2); } else if(strcmp(argv[1],"-div") == 0) { // 当被除数为0时,操作错误 if(d2 == 0) printf("%d / %d = error , div zero\n", d1 ,d2); // div , 将两个操作数相除 else printf("%d / %d = %d\n" , d1 , d2 ,d1 / d2); }else{// 当操作选项不为上述四个操作时,则说明输入错误,输出操作说明printf("Use error , you should use right command line\nUsage:%s op[add|sub|mul|div] d1 d2\n",argv[0]);}return 0;
}
二、环境变量
2.1 环境变量的基本概念
- 环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
- 在命令行中输入
echo $环境变量
命令可以查看当前环境变量的内容,这里环境变量前必须加上 $ ,否则环境变量会被当成字符串输出。
2.2 常见环境变量
2.2.1 PATH
之前文章提到过,要执行一个命令就必须找到对应的可执行程序,当我们平时要运行我们自己编写的程序时,都需要带上./
来代表该程序的路径,没有./
则找不到该程序导致无法运行,但是当我们使用指令(本质上也是程序)的时候发现并不需要./
来找到它的路径,例如ls、pwd、which
等命令,它们可以使用路径来运行指令,也可以直接使用指令的名字来运行指令,导致指令不需要路径就可以运行的原因就是PATH。
我们可以使用echo $PATH来查看环境变量PATH中的内容,这里必须加上 $ ,否则PATH会被当成字符串输出。
查看PATH中的内容发现它的内容是一个字符串,以 : 为分隔符,可以看出这个字符串是由许多路径组成的。当用户在命令行中输入一个指令或程序名时,系统会在PATH环境变量所指定的目录中搜索该指令或程序的可执行文件。如果找到了,系统就会执行它;如果没有找到,就会报错。
2.2.1.1 通过命令行配置PATH
-
向PATH中添加路径,可以使用PATH = PATH:/需要添加的路径,即可向PATH中添加路径
-
将PATH中的部分路径删除,可以使用PATH=/所需要的路径
当我们将PATH中所有的路径全部删除,会发现系统中的大部分指令无法正常的使用,但是当我们重新登录操作系统后,就可以发现指令可以正常使用了。
这是因为操作系统中有很多配置文件,有一类配置文件在命令行启动的时候会被读取,将预设的环境变量和对应的内容导入进操作系统。我们这里修改的环境变量只限于本次登录,重新登录后,环境变量会被重新加载。
2.2.1.2 使自己的程序像系统中指令一样运行
-
将自己编写的程序的路径添加的PATH中,可以使用PATH = PATH:/自己程序所在的路径
-
将自己编写的程序拷贝到PATH中的任意一个路径中,本质上就是程序安装
2.2.2 HOME
环境变量HOME指定了当前用户的家目录,这个路径通常看起来像是/home/用户名(对于root用户则是/root)。
当我们登录账号时,会发现普通账号与root账号的家目录是不相同的,是因为操作系统中有一个环境变量在我们登录时就存在了,当我们登录账号时,它会对用户进行识别,然后对不同的用户设置它不同的环境变量HOME。
我们经常使用 cd ~ 用来使用户快速回到家目录,本质上就是波浪线 ~
是对HOME环境变量值的快捷方式,表示当前用户的加目录。
2.2.3 PWD
环境变量PWD用于存储用户当前所在的目录(工作目录)的完整路径。
我们使用的指令pwd就是从环境变量PWD中读取,得到用户当前所在的工作目录。
2.3 查看操作系统中所有的环境变量(env)
在Linux系统中,env命令是一个非常重要的工具,用于显示或设置环境变量。当在命令行中直接输入env命令并按下回车键时,系统会列出当前设置的所有环境变量以及它们的值。
2.4 如何在进程中获取环境变量
2.4.1 getenv函数
在Linux中,getenv函数是一个标准C库函数,可以用于获取环境变量中的内容。char *getenv(const char *name);
- name:指向以NULL结尾的字符串的指针,该字符串为要查询的环境变量的名称。
#include<stdio.h>
#include<stdlib.h> int main()
{ printf("PATH:%s\n",getenv("PATH")); printf("HOME:%s\n",getenv("HOME")); return 0;
}
2.4.2 命令行的第三个参数(char* env[])
在上面命令行参数中,我们讲到了main函数可以不带参数,可以带两个参数,实际上main函数还可以带第三个参数char* env[]
,这第三个参数是指向环境变量字符串的指针数组,在操作系统启动的时候会一张是环境变量表,这张表中存放的就是环境变量字符串的地址。
Shell在启动我们程序的时候,可以选择给我们的进程(main)提供两个表,一个是命令行参数表,一个是环境变量表。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h> int main(int argc,char* argv[],char* env[])
{ int i = 0; for(; env[i] ; i++) { printf("my pid: %d , env[%d]: %s\n",getpid(),i,env[i]); } return 0;
}
当我们运行上面的程序时,可以发现程序打印出的环境变量与在命令行中使用env指令打印出的环境变量基本上完全一致。
2.4.3 全局变量environ(C语言/C++)
在Linux中,如果你在C语言程序中想要查看环境变量,你可以通过访问全局变量environ来实现。environ是一个指向以NULL结尾的字符指针数组的指针,每个指针都指向一个以NULL结尾的字符串。大家也可以理解为全局变量environ就是指向env表的指针。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h> int main()
{ extern char** environ; int i = 0; for(; environ[i] ; i++) { printf("my pid: %d , environ[%d]: %s\n",getpid(),i,environ[i]); } return 0;
}
2.5 进程如何获取环境变量
之前的文章中讲到过,在命令行上启动的进程都是Shell/bash的子进程,子进程的命令行参数和环境变量都是父进程传给子进程的。
在讲解PATH的时候提到过,当我们修改PATH再重新登录Shell后,PATH会被重新生成,这是因为我们修改的是bash进程内的环境变量,每次重新登录,操作系统都会给我们重新生成bash解释器并且新的bash解释器会自动从脚本配置文件读取形成自己的环境变量信息表,环境变量信息是以脚本配置文件形式存在的,bash进程的环境变量就是从脚本配置文件中获取的。
2.5.1 .bash_profile文件
位置:位于用户的家目录下,路径通常为/home/用户名/.bash_profile
,当我们在家目录下输入命令ls -al
会发现一个隐藏文件.bash_profile。
作用:在用户登录的过程中,系统会首先检查是否存在.bash_profile文件,如果存在,则会执行其中的命令,它主要用于设置用户级别的环境变量和执行用户特定的初始化脚本。
2.5.2 .bashrc文件
位置:同样位于用户的家目录下,路径为/home/用户名/.bashrc
。当我们在家目录下输入命令ls -al
会发现一个隐藏文件.bashrc。
作用:该文件是bash/Shell的启动脚本,用于配置用户的交互式Shell环境。每次启动一个新的bash/Shell时,.bashrc文件都会被执行,通常在.bash_profile文件中通过一行代码来加载.bashrc,以确保登录Shell也能加载.bashrc中的配置。
2.5.3 /etc/bashrc文件
位置:位于系统的/etc目录下,还有一个文件/etc/bashrc
。
作用:该文件为系统中所有运行bash/Shell的用户提供全局的bash配置。通常在.bashrc文件中通过一行代码来加载/etc/bashrc,当bash/Shell被打开时,该文件会被读取并执行,它通常包含一些对所有用户都适用的配置信息,如环境变量设置、别名定义等。
2.6 如何向进程中设置环境变量
在Shell/bash中不仅仅有系统的环境变量,还可以自己添加环境变量,下面为大家介绍两种添加环境变量的方法。
2.6.1 在命令行中设置环境变量
我们可以在命令行中设置变量,如下图,我添加了一个变量MYENV_1,并且这个变量可以通过echo指令显示变量的内容,但是当使用env指令并通过管道筛选出MYENV_1变量却显示不出来变量的内容,显然是因为这个变量没有被添加到环境变量中,其实这种变量我们称之为本地变量,本地变量与环境变量的区别在后面讲到,想要将本地变量添加到环境变量,使用export 本地变量名
即可。
除了先将变量定义出来再使用export添加到环境变量,还可以在定义变量的同时将变量export添加到环境变量中,例如:export MYENV_2=1314
。
要注意的是以export指令添加环境变量只在本次登录有效,当重新登录Shell/bash时,我们添加的环境变量就不会存在,因为我们添加的环境变量实际上是添加到Shell/bash进程中的,也就是内存中,重新登录后也就不会存在我们添加的环境变量。
当我们使用命令行启动进程,用来输出该进程的环境变量,发现我们添加的环境变量在该进程(Shell/bash的子进程)也存在,也能证明子进程的命令行参数和环境变量都是父进程传给子进程的。
2.6.2 修改系统中的配置文件
想要每次启动Shell/bash时,自己设置的环境变量都存在,可以通过修改 ~/.bashrc 、~/.bash_profile
等文件来永久设置环境变量。
我们在命令行中如何添加环境变量的,就在配置文件中怎么写。
2.7 本地变量 vs 环境变量
2.7.1 本地变量
本地变量是在Shell脚本或命令行界面中定义的变量,本地变量只在bash内部有效,无法被子进程获取。
2.7.2 环境变量
环境变量是对于运行在当前用户环境中的所有进程都可见的变量。它们通常由操作系统或Shell在启动时设置,但也可以由用户或程序在运行时设置。
2.7.2.1 环境变量通常是具有全局属性的
环境变量通常具有全局属性,这意味着它们一旦被设置并导出到环境中,就会对当前Shell/bash进程及其启动的任何子进程可见。
当我们运行下面这个程序的时候,可以发现子进程的子进程也可以获取到环境变量,也可以证明环境变量通常具有全局属性的。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h> int main()
{ int id = fork(); if(id == 0) { extern char** environ; int i = 0; for(; environ[i] ; i++) { printf("my pid: %d , environ[%d]: %s\n",getpid(),i,environ[i]); } } return 0;
}
2.8 命令常见分类
不知道大家在上面部分有没有注意到一个小细节,就是当把环境变量置为空时,大部分都无法运行,但是还是有小部分命令可以运行,因为命令被分为了两种,常见命令与内建命令。
2.8.1 常见命令
常见命令是Linux系统中的实用程序部分,它们通常位于/usr/local/bin、/usr/bin、/usr/local/sbin或/usr/sbin等目录下。这些命令由独立的程序实现,当这些命令运行在命令行上启动时,Shell/bash会创造一个子进程来运行这个命令,当我们将环境变量PATH置为空以后,那么常见命令就不能够通过命令名直接启动进程。
例如:
-
ls:列出目录内容。
-
cp:复制文件或目录。
-
mv:移动或重命名文件。
-
rm:删除文件或目录。
-
ps:显示当前运行的进程。
-
grep:在文件中搜索指定文本。
-
tar:用于压缩和解压文件和目录。
2.8.2 内建命令
内建命令是Shell/bash进程的一部分,它们由Shell/bash进程识别并在Shell/bash进程内部完成运行。与常见命令不同,执行内建命令时不需要创建新的子进程,因此它们的执行速度通常更快。
例如:
- cd:切换工作目录。
- pwd:显示当前工作目录的路径。
- echo:输出字符串或变量值。
- read:从标准输入读取数据。
- set:设置或显示Shell环境变量与本地变量。
- unset:删除Shell环境变量与本地变量。
2.9 和环境变量相关的命令
-
echo: 显示某个本地变量与环境变量值
-
env: 显示所有环境变量
-
export: 设置一个新的环境变量
-
unset: 清除本地变量和环境变量
-
set: 显示本地定义的shell变量(本地变量)和环境变量
结尾
如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹