【linux】-进程概念之环境变量的详解(命令行参数的介绍)

💖作者:小树苗渴望变成参天大树🎈

🎉作者宣言:认真写好每一篇博客💤

🎊作者gitee:gitee

💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录


前言

今天我们来讲解一个之前陌生而又熟悉的知识---环境变量,有的同学听过,有的同学没有听过,之前学过java和python的应该配置过环境变量,但是还是不太了解,接下来这篇就带大家来重新认识什么是环境变量,环境变量有什么作用,我将先带大家认识几个常见的环境变量,然后再跟大家说明什么是环境变量,这样大家才能更好的理解,话不多说,我们开始进入正文的讲解


一、常见的环境变量

和环境变量相关的命令
1. echo: 显示某个环境变量值
2. export: 设置一个新的环境变量
3. env: 显示所有环境变量
4. unset: 清除环境变量
5. set: 显示本地定义的shell变量和环境变量

常见环境变量

PATH : 指定命令的搜索路径

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

SHELL : 当前Shell,它的值通常是/bin/bash。

1.1PATH

我们来写一个程序

c 复制代码
  1 #include<stdio.h>
  2 
  3 int main()
  4 {
  5     int i=0;
  6     for(;i<5;i++)
  7     {
  8         printf("hello,%d\n",i);                                                                                                             
  9     }
 10     return 0;
 11 }

我们之前也说过,指令也是程序,和我们写的程序没什么区别,为什么我们自己写的程序需要加./来运行而指令却不需要,是因为什么,我们之前说过指令再指定路径下,系统会自动找到的,我们自己写的程序,系统是默认找不到的,原因就是因为PATH变量里面没有我们当前的查找路径,我们来看看PATH变量里面是什么:使用echo $PATH

我们PATH里面有许多好几个默认查找路径,以冒号进行分割的。我们看到我们的指令路径再我们的PATH下,所以可以查到,而我们自己写的程序却直接运行不了出现了not found说明他是搜索过的,只是没有查找到。


可以将我们写的程序放到默认的指令路径下,按照指令的模式一样运行,今天我们不使用这样的方式,我们把需要运行程序的路径放到PATH变量里面,是不是就可以像指令一样的运行了??

使用PATH=$PATH:路径这是追加路径

我们达到我们想要的效果了,等号两边不需要空格

使用PATH=路径这是覆盖原路径

我们发现我们的原来指令都跑不了了,但是pwd可以跑,这个后面再介绍原因,那我们应该怎么办,大家不要担心,这些修改都是bash进程下修改的,等退出登录的时候bash被销毁,下次再登录的时候就又恢复之前的样子了。

通过上面的介绍,我们写的程序还有系统的指令程序都是由路径的,使bash通过PATH变量里面路径帮助我们去查找,就算没有找到也是bash说没有找到,希望大家可以理解这个原理

1.2HOME和SHELL

我们使用whoami的时候,系统怎么知道我们的的名字的,原因就是我们的HOME变量有我们对应的用户,我们来使用env查看一下所有环境变量:

我们只需要看看这几个我圈出来的这几个环境变量就行了,这下面还有一些环境变量

OLDPWD这是上一次的用户目录

这是因为有了这个OLDPWD环境变量,我们可以实现使用**cd -**再两个用户直接来回切换,一会会介绍到怎么做到的,使用选项再里面由判断条件,对应不同的功能

所以我们的whoami、pwd 等一些指令为什么会达到我们想要的效果,就是因为有这样环境变量。

1.3使用系统调用接口来获取环境变量

getenv这个函数我们来看一下文档:

我们来修改第一次写的程序:

c 复制代码
#include<stdio.h>
#include<stdlib.h>
int main()
{
    printf("PATh:%s",getenv("PATH"));
    return 0;
}

我们看到也可以用系统调用接口来获取此进程所拥有的环境变量。注意传参是传环境变量的字符串

接下来让大家再次理解权限的概念:看代码:

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    char who[32];
    strcpy(who,"root");
    if(strcmp(who,getenv("USER"))==0)
    {
        printf("你可以做任何事情\n");
    }
    else 
    {
        printf("你是普通用户,受限制\n");
    }
    return 0;
}

相同的代码,再不同的用户登录去运行结果就是不一样的,我们权限也是类似于这样的设计。


上面我们介绍了常见的环境变量,也知道了环境变量的作用以及重要性,那什么是环境变量我还没有具体下定义:他是系统提供的一对name=value的
形式的变量,不同的用户具有不同的环境变量,环境变量通常具有全局性
,对于全局性我需要铺垫下面的知识,才能让大家更好的理解,命令行参数

二、命令行参数

相信大家对这个名词应该是非常的陌生的,但是对于这个东西可能见过,学过java的应该都有看过,但是没有具体使用过,为什么要有命令行参数以及怎么使用的一会都会介绍到。

我们一个程序是从主函数开始调用的,主函数也是函数,就存在调用和被调用关系,既然有参数肯定是通过别的函数调用主函数进行传参给主函数,才可以,接下来我们来看代码:

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

我们第一个参数是传了几个参数进来,第二个参数是一个指针数组,存放传进来的字符串,我们来看看运行效果:


按照上面说的,我们的结束条件也可以设置成下面这样: for(;argc[i];i++)

大家目前还是不懂什么意思,接下来再写一个代码大家就知道了:

c 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char*argv[])
{
    if(argc!=2)
    {
        printf("./cmd -[a|b|c]\n");//按照此格式进行运行
    }
    if(strcmp(argv[1],"-a")==0)
    {
        printf("功能1\n");
    }
    else if(strcmp(argv[1],"-b")==0)
    {
        printf("功能2\n");
    }
    else if(strcmp(argv[1],"-c")==0)
    {
        printf("功能3\n");
    }
    else 
    {
        printf("没有此功能\n");
    }

    return 0;
}

到这里我们的结论就出来了,命令行参数是为指令、工具软件提供命令行选项的支持


三参数的命令行参数:

大家有所疑问,我们不是再介绍环境变量吗,怎么说到这个了,他们有什么关系呢,真的有很大的关系,那第三个参数是什么呢?他是一个和第二个参数一模一样的类型,是一个指针数组的存放的环境变量,我们使用env看到许多环境变量,其实放在指针数组里面的,每一行其实都是使用双引号括起来的字符串,我们的getenv是获取一个环境变量,通过第三个参数我们可以获取所有的环境变量,我们来看代码:

c 复制代码
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
	 int i = 0;
	 for(; env[i]; i++)
	 {
		 printf("%s\n", env[i]);
	 }
 return 0;
}

我们通过第三个参数也可以把所有的环境变量给显示出来,不需要使用env了。

到这里给大家解释一个概念:

通过上面两个代码的演示,我们已经知道了第二个参数,以及第三个参数的作用了和效果,那这两个参数到底是什么,我们说过这两个参数都是指针数组,分别指向两个不同的数组,这两个数组一个是命令行参数表,一个是环境变量表

我们刚才运行的cmd程序原本是没有环境变量的,但是我们运行的时候形成了一个进程,此进程是bash进程的子进程,换句话说,子进程的环境变量是由父进程将自己的环境变量表和命令行参数表传给子进程,才打印出来的,子进程会继承父进程的环境变量表,而bash再启动的时候,也是os的子进程,他的环境变量信息是通过os的配置文件来获取的,我们参数不写也会直接继承。


怎么证明是继承下来了,通过env和子进程打印出来的都是一样的,是系统一开始就有的,那我们不确定是父进程继承下来的,还是系统的环境变量的?

此时我们就需要再bash进程里面添加一些特有的环境变量,看看此时子进程有没有这个特有的环境变量,是不是就达到验证了,那么问题来到我们怎么添加新的环境变量呢??
export name=value

我们不带export定义的变量是本地变量,不会被继承,一会说,我们需要使用export将环境变量进行导入,我们看到效果,确实被继承下来了,先要删除环境变量要通过unset name就可以删除了。

通过上面的一系列介绍,我们知道了每个进程的环境变量是怎么通过系统接口获取的,一旦bash进程没了那其他进程的环境变量也都没有了,还记得我们给出环境变量概念的时候,说过环境具有全局性,通过命令行参数的讲解,大家有没有理解环境变量具有全局性的特点。

三、本地变量和内建命令

3.1本地变量

再上面我们提到过不带export定义的变量叫做本地变量,我们来看看本地变量的是什么,为什么要定义本地变量,本地变量不会被继承怎么验证

  1. 本地变量是什么

    就是再命令行上直接定义的变量,不会出现再环境变量表里面的,使用env是看不到的,但是实际上是存在的

  2. 为什么要有本地变量

    本地变量是给本地使用的,当前进程特有的一个功能,我们来看看bash的本地变量,使用set查看所有的环境变量以及本地变量

    这是我截取的一部分有本地变量的。第一个是命令行提示符,这个只是bash自己使用就好了。

  3. 怎么验证没有被继承

    我们只有使用export定义的变量才会被进程,没有导入就继承不了。

相信大家对这个本地变量应该有所了解了吧

3.2内建命令

我们定义了本地变量,我们所有的指令都是bash进程的子进程,刚才说过本地变量不会被继承,那我们echo指令式怎么获取定义的本地变量??换句话说echo到底有什么创建自己的进程??

有两批指令:

  1. 常规指令--创建子进程完成的
  2. 内建指令--不需要创建子进程,由bash自己去完成的,就是bash自己会调用自己内部的函数去完成的

bash也是一个程序,由自己的函数,接下来我就带大家来演示一个内建命令cd,这是求换目录的,我们来看看代码:

c 复制代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
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;
}

我们的程序通过系统调用接口改变了路径,那我们的bash对于cd命令的时候采取的这样的方式去直接带哦有了这个系统调用接口

c 复制代码
if(strcmp(argv[1], "cd")==0)//先判断,然后自己去调用
{
    chdir(argv[1]);
}

这样bash就不需要创建子进程给内建命令了。我们的pwd也是内建命令,他不再PATH里卖弄为空的情况,不像其他常规指令一样将环境变量继承下来,然后发现没有路径可以查找就使用不了,而内建命令式直接通过调用自己的函数去实现的,所有没有PATH也是可以直接运行的,而不是去找其他程序去运行别的程序函数去运行的。

到这里大家对于内建命令应该有所了解了。也明白了环境变量的作用以及重要性了

四、总结

说到这里我们对于环境变量的学习就到这里了,大家至少要掌握为什么要有环境变量,还由命令行参数,这个是非常重要的,希望大家下来自己可以很好的去理解,下一篇博主就会讲解关于进程概念的最后一个主题:进程地址空间,到时候会给大家解决之前留下来的问题,一个变量怎么保存不同的值,希望大家可以来支持博主,我们下篇再见。

相关推荐
yaosheng_VALVE6 分钟前
稀硫酸介质中 V 型球阀的材质选择与选型要点-耀圣
运维·spring cloud·自动化·intellij-idea·材质·1024程序员节
看山还是山,看水还是。1 小时前
Redis 配置
运维·数据库·redis·安全·缓存·测试覆盖率
扣得君1 小时前
C++20 Coroutine Echo Server
运维·服务器·c++20
keep__go1 小时前
Linux 批量配置互信
linux·运维·服务器·数据库·shell
矛取矛求1 小时前
Linux中给普通账户一次性提权
linux·运维·服务器
Fanstay9851 小时前
在Linux中使用Nginx和Docker进行项目部署
linux·nginx·docker
大熊程序猿1 小时前
ubuntu 安装kafka-eagle
linux·ubuntu·kafka
jieshenai2 小时前
使用VSCode远程连接服务器并解决Neo4j无法登陆问题
服务器·vscode·neo4j
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss
Gentle5862 小时前
labview连接sql server数据库
服务器·数据库·labview