【Linux】进程5——环境变量,命令行参数

1.什么是环境变量

环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数

  • 比如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
  • 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

windows里也有环境变量

 2.认识几个环境变量

2.1.PATH

  1. PATH : 指定命令的搜索路径

        为什么我们使用指令时不用加./,而我们使用自己编译的可执行程序就需要加./?

        这个是因为使用指令的时候,系统默认在/usr/bin/里去查找,那我们自己的可执行程序为什么没有这个待遇?
        原因在于linux会给指令搜索提供一个环境变量PATH

我们可以把它显示出来

查看环境变量指令:
echo $NAME //NAME:你的环境变量名称 

        上图是我Linux用户下的PATH变量,这些路径都由:进行分隔。

        当我们输入我平时的ls、pwd等等指令时直接就可以使用,就是因为他们都是在/user/bin目录下,操作系统可以自动寻找。

        但是我们运行一个陌生路径下的可执行程序时就得声明为当前路径下,这就是因为我们在PATH环境变量中没有定义此路径。操作系统不能自动寻找。

        我们可以将一个程序放到PATH有的路径下,或者将当前的绝对路径加入到PATH变量中去,我们就可以直接使用此指令。

        

        我们可以往PATH添加路径

        这样子这个/home/zs_108目录下面的所有可执行程序都能当成指令来运行了

实际上,我们刚刚修改的PATH环境变量是一种在内存中的环境变量,所以无需担心。

如果不小心改错了,只需关闭Xshell并重新登录即可。这个PATH环境变量是在shell中保存的。

然而,当shell尚未存在时,即在系统启动时,环境变量是从哪里来的呢?

        实际上,这些环境变量预先存储在我们系统的一些配置文件中。当系统启动时,它们会被加载到内存中。因此,现在你不必担心你的环境变量被错误修改,只需重新启动一下,我们的环境就会恢复

PATH的几个注意点:

  1. 不同身份用户默认的PATH不同,默认能够随意执行的命令也不同(如 root与dmtsai);
  2. PATH是可以修改的;
  3. 使用绝对路径或相对路径直接指定某个命令的文件名来执行,会比查找 PATH来的正确;
  4. 命令应该要放置到正确的目录下,执行才会比较方便;
  5. 本目录(.)最好不要放到PATH当中。

2.2.HOME

  1. HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时默认的目录)

        在我们平时登录xshell的时候普通用户就会直接进入自己的家目录/home/xxx而root用户会进入自己家目录/root ,那么系统是怎么知道我们的工作目录的呢?

      主要原因就是因为当我们在登录时,shell就会直接识别到当前登陆账户是谁,然后给当前用户填充$HOME环境变量,当我们登录时,此时默认就直接cd到了$HOME目录下。这就是我们每次登录之后都会处于自己对应的家目录的原因。

2.3.Shell

我们怎么知道我们使用的是哪个SHELL呢?

2.3.获取环境变量env&&getenv

bash中我们可以使用env命令来获取bash从系统中继承下来的所有环境变量

我们可以通过下面这个来查询其他环境变量

我们讲解HISTSIZE这个环境变量——他代表的是我们的Linux记录下的最新的HISTSIZE条操作,

我们可以使用history命令来获取

 我的账号还没有达到10000条

除了env命令,我们也可以使用系统调用接口的getenv函数来获取某一个环境变量。 

我们看一下使用getenv来获取PATH环境变量的例子 

#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
    cout<<"PATH="<<getenv("PATH")<<endl;
    return 0;  
}

很好用吧! 

2.4.环境变量USER

  USER环境变量用来标识当前登录的用户。在终端中输入命令echo $USER,可以查看当前登录用户的用户名。这个环境变量是bash/shell在启动时自动加载的,它记录了当前登录的用户。

       我们来使用getenv来获取USER的代码:

#include <iostream>
#include <unistd.h>
using namespace std;

int main()
{
    cout<<"USER="<<getenv("USER")<<endl;
    return 0;  
}

了解了上面内容,我就可以模拟一下系统权限对普通用户和root用户的判定方式:

#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;

int main()
{
    char who[32];
    strcpy(who,getenv("USER"));
    if(strcmp(who,"root")==0)
        cout<<"root用户不受条件约束"<<endl;
    else 
        cout<<"普通用户受权限约束"<<endl;
    cout<<"USER:"<<getenv("USER")<<endl;

    
    return 0;  
}

 

 因为有环境变量的存在,我们的系统就已经具备了能够认识你这个人是谁的能力,只要能认识你是谁,就可以和文件属性当中文件的拥有者所属组和文件所对的权限所对比,进而判定出你有没读写权限

3.命令行参数

我们C/C++中的main函数其实是可以带有参数的,就像下面这两个,这两个参数我们称之为命令行参数:

int main(int argc, char* argv[ ])

其中argv是一个指针数组,里面保存了字符串(字符是谁我们后面再说)的地址,argc决定了argv中的元素个数,我们来尝试打印一下argv中的内容:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
  
int main(int argc, char* argv[])
{
    for(int i = 0; i < argc; i++)
    {
      printf("argv[%d] == %s\n", i, argv[i]);                                                                                                          
    }
    return 0;
}

我们在命令行输入几个数后,打印出来就有几个。

main()是c/c++程序第一个被调用的函数

        我们在命令行里执行可执行程序的时候输入的那些命令都被当成main函数的参数传进去

3.1.命令行参数的作用

那命令行参数有什么用呢?看代码:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char* argv[])
{
	if (argc != 4)//命令行参数不是4个的话
	{
		printf("Usage: \n\t%s -[add|sub|mul|div] x y \n\n", argv[0]);
	}
	int x = atoi(argv[2]);
	int y = atoi(argv[3]);

	if (strcmp("-add", argv[1]) == 0)//将第一个命令行参数和-add进行比较
	{
		printf("%d + %d = %d\n", x, y, x + y);
	}
	else if (strcmp("-sub", argv[1]) == 0)//将第二个命令行参数和-sub进行比较
	{
		printf("%d - %d = %d\n", x, y, x - y);
	}

	else if (strcmp("-mul", argv[1]) == 0)
	{
		printf("%d * %d = %d\n", x, y, x * y);
	}
	else
	{
		printf("%d / %d = %d\n", x, y, x / y);
	}
	return 0;
			
}

这看起来怎么这么熟悉啊?

命令行参数是Linux指令的基础,从上面的程序我们可以联想出我们在Linux中使用的指令后面跟的就是命令行参数:

我们使用的ls -al 、ls -al等等都是命令行参数。

        命令行参数可以通过输入不同的选项,来控制程序执行不同的功能代码。
        命令行参数为指令,工具,软件等提供命令行选项的支持! 

3.2.main函数的第三个参数

我们上面讲了main的的两个参数,那它和环境变量有什么关系?

我们先来看下面的例子

#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;
int main(int argc,char *argv[])
{
	for(int i = 0;argv[i];i++)//执行到argv[i]=NULL的时候循环就会停止 
    {
        printf("argv[%d]->%s\n",i,argv[i]);
    }
	return 0;
}

这个是什么意思呢?

指针数组最后都是以NULL来处理未使用的空间的,所以当执行到argv[i]=NULL的时候循环就会停止 

所以它和下面这个是等价的

#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;
int main(int argc,char *argv[])
{
	for(int i = 0;i<argc;i++)
    {
        printf("argv[%d]->%s\n",i,argv[i]);
    }
	return 0;
}

 

上面我们使用了

main函数除了上面那两个参数,还有一个叫做char *env[]的参数;

int main(int argc,char *argv[],char *env[])
{
	return 0;
}

这个char* env[]是个什么啊?

  我们也可以来打印一下env中的内容:

#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;
int main(int argc,char *argv[],char* env[])
{
	for(int i = 0;env[i];i++)
    {
        printf("env[%d]->%s\n",i,env[i]);
    }
	return 0;
}

 这个怎么和env获得的东西一模一样啊!!!!!哈哈被你猜对了 

这个env[]参数就是所有环境变量

还可以通过第三方变量environ获取

#include <stdio.h>
int main(int argc, char *argv[])
{
	extern char **environ;
	int i = 0;
	for(; environ[i]; i++){
	printf("env[%d]->%s\n",i,environ[i]);
	}
	return 0;
}

argv和env的结构一模一样,所以我们的C/C++代码一共会有两张核心向量表,一张叫做命令行参数表,一张叫做环境变量表。

环境变量表会从父进程中继承下来。

我们所运行的进程,都是bash的子进程, bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我的环境变量!

3.3.验证环境变量的继承

环境变量通常具有全局属性,可以被子进程继承下去

我们可以自己定义一个环境变量导入系统中的环境变量表当中,我们想要增加一个环境变量可以使用下面命令:

export MY_VALUE=666666666666

可以看到我们自己定义的环境变量已经被导入到环境变量表当中。

我们接下来再去执行我们刚刚的代码:

看到env[17]了嘛!!!可以发现它里面也有 MY_VALUE 这个环境变量,说明子进程test继承了父进程 bash 的环境变量。

删除一个环境变量可以使用unset 环境变量命令。

unset MY_VALUE

4.常规命令&&内建命令

4.1.什么是本地变量

我们再来看这个图中,我们定义了本地变量MY_VALUE,我们的可执行程序(bash的子进程)都读不到这个变量,为什么echo可以读取到呢

我们使用可执行程序test去读取我们的本地变量

我们定义了一个本地变量MY_VALUE,它的值是123456

我们说我们在执行一条命令的时候,bash进程都要创建一个子进程

那这个echo呢? 

 其实我们命令行上执行的指令不一定都要创建子进程,就好比王婆说媒一样,一些有任务特别难的或者风险的,王婆就会找别人去帮忙说媒。

如果是一些很有把握的事情,那王婆还是愿意自己去做的。

由此可以推出我们指令是有区别的:

  • 常规命令:通过创建子进程完成的
  • 内建命令:bash不创建子进程,而是有自己亲自执行,类似于bash调用了自己写,或者系统提供的函数。

所以echo是一个内建命令,它是由bash自己执行的,与此同时我们的cd命令也是一个内建命令,我们可以通过调用chdir来改变当前工作目录。

#include <iostream>
#include <unistd.h>
#include <cstring>
using namespace std;
int main(int argc,char *argv[])
{
    sleep(30);
    printf("change begin\n");
    if(argc==2)
    {
        chdir(argv[1]);
    }
    printf("change end\n");
    sleep(30);
    return 0;
}

在命令行中输入 cd 命令的时候,bash 并不会创建子进程,而是去判断命令行参数是否为 cd,如果是就直接去调用 chdir 系统接口来切换bash的工作目录 

  • 46
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值