本篇要分享的内容关于Linux新操作系统中命令行参数。
命令行参数本质上还是作为以后的环境变量的基础来学习的,所以在接触更高难度的内容之前先学习基础。
以下为本篇目录
目录
[3.3. root和普通用户的家目录](#3.3. root和普通用户的家目录)
1.main函数的参数?
我们学习的main函数是否能传参呢?
在我们之前学习C语言包括我们现在所学习的C++,main函数都是不传参的
cpp
#include<stdio.h>
int main()
{
printf("hello world");
return 0;
}
既然main函数也是函数,那么main函数也是要被调用的
被谁调用我们以后再说
今天这里要说的是main函数也可以是有参数的。
cpp
#include<stdio.h>
int main(int argc,char *argv[])
{
printf("hello world\n");
return 0;
}
可以看到上面代码中main函数增加了两个参数
cpp
int argc,char *agev[]
这在我们语言的参数中是很少用到的,是因为我们在之前的语言的学习中的代码较为简单,用不上mian函数中的参数。
现在我们要知道,这样的参数叫做命令行参数。
第一个参数 int argc 虽然我们不明白它的意思,但是他是一个int类型的数据,和数字有关
第二个参数 char *argv[] 单纯站在我们不考虑函数时,他是一个单纯的指针数组,这个数组中存放的都是一个个char*
至于两个函数的意思我们观察下面C语言的代码
cpp
#include<stdio.h>
int main(int argc,char *argv[])
{
for(int i=0;i<argc;i++)
{
printf("%d:%s\n",i,argv[i]);
}
printf("\n");
return 0;
}
1.既然argc为int类型,我们不妨使用参数中的argc来作为for循环的上限;
2.并且我们知道在C语言中是没有字符串类型的数据的,C语言中的字符串类型的数据只能是char类型的字符数组,所以我们不妨使用通过遍历将argv中的元素内容打印出来
下面我们将代码运行起来
可以看到对应上面的代码,argc为0,argv对应输出的字符串为./myproc
下面我们继续在命令行中输入-a
可以看到输出多了一行,并且argc为1,argv数组中的字符串也变成了-a
那我们不妨继续在命令行输入命令并输出
可以看到他都可以统计出我我们在命令行中输入的内容并输出。
到现在为止,我们需要与之前的代码进行对比
不难看出main函数中的argc就是命令行中以空格结尾的,输入的多少串字符串。
可以看到在最后一次的输入中我们输入了五个字符串,并且以空格结尾,所以argc就为5。
在理解argv这个指针数组时,首先我们要先将我们在命令行中输入的数看作为一整个大的字符串
(大字符串)。
同时我们以空格作为分隔符,把小的字符串化作一小个区域
(每个黄色框是一小个区域)
这里一整个大字符串就被分为了5个子串。
那么在argc的指针数组中呢他会将每个地址都记录下每一个字符串串的首地址
(注意每个指针指向的时字符串的首地址)
但是这个指针数组最后必须要流出来一个空间来指向NULL,以NULL来结尾 。
在我们了解完这些参数的意义之后,就需要来研究这些代码是由谁来做的,怎么做的,因为我们在使用命令行时从来都没有做过这些工作。
因为这些工作都是操作系统,自动帮我们完成的。
也就是说我们在一命令行启动一个程序的时候,我们会以空格作为分隔符(或者理解为\0), shell或者操作系统会自动将我们输入的字符串打散,统计argc的个数,传参给我们的main函数,并且在系统中生成argv指针数组的表并传给我们,所以我们才能看到上面输出的内容。
2.命令行解释器意义
这里打算模拟实现一个计算器来理解命令行解释器的原理
我的设计思路是输入一行字符串,通过分隔符将字符串分为四个部分的内容
第一个被分割内容:./myproc表示我所要运行的程序的名称
第二个被分割内容:add表示我所要进行的是加法运算
第三个被分割内容:1表示加数
第四个被分割内容:2表示第二个加数
以上是我的测试输入,有四个部分的内容,那么我的模拟计算器的代码如下
cpp
int main(int argc,char *argv[])
{
if(argc!=4)
{
printf("Use error\nUsage: %s op[add|sub|mul|div] d1 d2\n",argv[0]);
return 1;
}
int x=atoi(argv[2]);
int y=atoi(argv[3]);
int result=0;
if(strcmp(argv[1],"add")==0)
{
result=x+y;
printf("%d+%d=%d\n",x,y,result);
}
else if(strcmp(argv[1],"sub")==0)
{
result=x-y;
printf("%d+%d=%d\n",x,y,result);
}
else if(strcmp(argv[1],"sub")==0)
{
result=x-y;
printf("%d-%d=%d\n",x,y,result);
}
else if(strcmp(argv[1],"mul")==0)
{
result=x*y;
printf("%d*%d=%d\n",x,y,result);
}
else if(strcmp(argv[1],"div")==0)
{
if(0==y) printf("%d/%d=error! div zero\n");
printf("%d/%d=%d\n",x,y,x/y);
}
else
{
printf("Use error\n");
}
}
模拟计算器的代码逻辑也都非常简单这里就不细说了,还可以有更简单的写法,我们主要的问题放在命令行解释器中。
完成这样一个计算器之后我们就可以实现各种运算
包括我们之前讲到的 ls 命令 ,它后面也可以根很多的命令
我们的touch命令用来创建文件,后面也可以加上需要执行的内容
可以看到我们只执行了touch命令他告诉我们使用的方法不对,使用touch --help查看更多信息
我们使用touch --help就可以得到touch的使用方法
可以得出结论:我们第一个输入的总是我们想要执行的程序,再往后输入的都是字符串,通过分隔符分开,以命令行参数的形式传递给main函数中的两个参数,再通过系统内代码的识别来达到同一个程序实现不同的功能。
3.环境变量
3.1.PATH环境变量
当我们再命令行输入指令的时候,指令就是程序的名称,命令行解释器会帮我们执行我们的程序,像我们平时都会使用的 ls、ll、pwd、who等等指令,他们都可以理解为程序。
但是这些程序都不需要我们额外的输入 ./ 去执行,我们在运行自己的代码时需要手动输入 ./ 才能运行我们的程序,那这些原因就和环境变量的配置有关。
在了解环境变量之前我们需要知道,需要执行一个命令,必须先要找到对应的可执行程序。
比如我想输ls展示我的当前文件的内容,但是我输成了la
命令行解释器找不到对应的可执行程序。
这也就是为什么我们执行我们自己编写的程序的时候需要加上 ./
因为 ./中的 . 符号代表着当前路径
我们之前所学的各种命令都存放在 /usr/bin目录中,所以我们根据程序的目录输入命令也是可以的
可以看到两种ls的 结果都是一样的。
像这种可以直接执行的命令它们有默认的搜索路径。
在Linux系统当中存在环境变量,它会直接记录我们可执行程序的搜索路径,这个环境变量就叫做:PATH
环境变量名叫做PATH,其对应的内容我们可以根据echo $PATH指令来查看环境变量的内容
可以看到其中有很多的冒号(:),那么这些冒号在这里作用就是分隔符,将一个个搜索路径分成一个个字串,所以当我们执行命令时,会在上面图中的搜索路径中,以冒号作为分隔符,一个一个的按照顺序去搜索我们当前所要执行的命令。
所以和上面的ls连接起来
因为ls命令在上图中的文件路径中,所以我们输入ls回车键,它便可以直接运行。
它不能执行myproc指令,就是因为myproc没有存在系统的环境变量中,也就是搜索路径中,所以我们的程序时执行不了的。
那我们想要直接执行我们的程序应该怎么做呢?
首先pwd查看当前所在位置,只要把当前所在的位置,添加到环境变量的搜索目录中即可。
PATH=$PATH: 追加搜索路径
可以看到我们使用上面的方法将当前路径添加到了环境变量的搜索路径当中。
所以我们在执行我们自己写的代码时就可以直接运行。
所以我们学习java时安装的 java解释器、java编译器或者Python解释器等等在Windows系统中默认的环境变量是找不到的,所以我们需要将这些软件添加到环境变量即可。
同样的如果我们需要删除一些搜索路径我们只需先查看当前的路径,选择需要的路径复制,将之前的路径覆盖即可
PATH= 修改的路径
可以看到我们祛除了自己编写代码的文件路径,所以不能再直接运行我们的代码。
3.2.PWD环境变量
当我们使用pwd来查看自己当前所在的位置时,pwd是如何知道我们的位置呢?
在我们的系统当中也存在了一个环境变量叫做PWD
PWD是当前对应的bash专门记录当前目录的一个环境变量
也就是说pwd执行的命令就是打印环境变量PWD中的内容
3.3. root和普通用户的家目录
当我们使用自己的机器时和账号时,或者使用root的时候,我们pwd观察自己所在的位置,
你会发现root和我们自己所使用的目录是不同的。
我们每个用户对应的Linux系统中都有不同的家目录,root账号所对应的家目录就是/root,我们普通用户所对应的家目录就在/home下。
那为什么会root和普通用户所在家目录不同呢?
首先要说的是在我们的系统中有一个环境变量,它比我们使用用户登录之前准备的还要早。
这个环境变量会默认识别出我们登录的身份(root或普通用户)
识别之后会根据相应的身份配置环境变量
可以看到这里的HOME同业也是环境变量名,echo $HOME可以查看对应的环境变量的内容。
也就是说HOMO变量中存放的就是我们登录之前系统识别我们身份后的所配置的环境变量,也就是路径;
在登陆前,系统只需执行
cpp
cd $HOME
用户即可达所以对应的配置的路径中。
所以按照登录的顺序我们可以分为以下几个部分
1.输入用户名和密码
2.认证
3.形成环境变量(包括PWD,PATH,HOME等)
4.根据用户名初始化root或普通用户
5.cd $HOME
3.4更多环境变量
像如上所说的环境变量在系统中还存在许多,我们在命令行中输入
cpp
env
即可查看更多系统中的环境变量
例如HOSTNAME
,这个变量是指主机名。
,这里的HOME变量我们也验证过。
,这里的变量名指的是最多可以记录多少条指令。
,USER指的就是我们当前客户端使用的用户。
这里的LS _COLORS指的是使用ls输出的字体的颜色。
更多的环境变量不过多赘述。
通过以上内容呢,我们知道系统中有很多环境变量,他们都有自己的 特殊用途,用来完成特定的系统功能。
4.获取环境变量
我们使用man getenv命令查看手册
可以看到getenv的使用方法,它的参数就是我上面所列举出来的环境变量名,返回值为char,无疑返回的是环境变量的内容。
我们使用getenv调用PATH就可以看到PATH的内容
getenv中只要是一个环境变量名,都可以得到其对应的内容。
比如上面讨论到的"USER"变量
我们对代码修改
可以看到同样可以得到USER环境变量的内容
5.环境变量的简单应用
在环境变量的学习中我们可能会遇到如下情景:
如果我们只想将我们的代码交给root来运行,其他的普通用户没有资格和权限来运行我的程序
我们需要做身份认证,只允许root来执行
代码如下
cpp
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
char *who=getenv("USER");
if(strcmp(who,"root")!=0)
{
printf("%s,非法用户访问!\n",who);
return 1;
}
printf("you can do");
return 0;
}
首先查看我们的用户名
然后我们执行这个文件
可以看到我们无法执行。
我们将身份切换到root用户来执行我们的代码
可以看到代码顺利执行了
两者执行结果的不同.
以上就是对环境变量的简单理解和简单的使用场景的介绍,本人水平有限,有误之处请指出批评,如果对您有所帮助还请三连支持,感谢您的阅读。