【Linux】Linux环境变量的理解 --- 命令行参数、shell子进程、环境、本地变量…



一、环境变量PATH中的系统默认搜索路径

1.将程序安装到/usr/bin目录不带./运行自己写的程序

1.
我们平常所用的Linux指令其实也是可执行程序和我们自己写的二进制程序没什么两样那么为什么在执行自己的程序的时候需要加上./而执行这些系统提供的指令可执行程序不需要加上./呢

在这里插入图片描述

2.
要执行一个程序或者指令必须先找到这个程序。
这也就是为什么我们在执行自己写的程序时要加上./当前路径这其实就是为了找到我们所写的程序而系统指令实际上是系统默认帮我们找到其程序的位置并且执行如果想不带./的执行自己的程序那就需要将程序安装安装的本质就是拷贝到/usr/bin目录下面也就是系统安装指令的路径当中

但不建议将自己的程序安装到系统默认路径下因为你的程序是未经过严格测试的会污染系统的指令池的所以如果你安装了的话建议玩完儿之后再把它删了吧
在这里插入图片描述

2.将程序路径添加到PATH环境变量里面不带./运行自己写的程序

1.
为什么在/usr/bin路径下的程序系统就可以找到呢其实是因为系统里面存在环境变量PATH操作系统在启动的时候会在shell的上下文当中定义一个PATH变量这个变量是全局有效的如果想要查看内容可以利用echo命令并且在PATH前面要加$符号。

2.
在执行系统指令的时候系统会默认去PATH环境变量里面的路径查找我们输入的指令程序如果找到系统就会执行这个程序如果没有找到就会报错command not found所以如果想要不带./执行自己的程序还有一种办法就是将自己所写的程序所在的路径添加到环境变量PATH里面。
我们可以任意修改PATH的值因为只要重新退出登录PATH环境变量就又会恢复了

在这里插入图片描述
3.
export可以用来将shell变量导入到环境变量PATH里面导入的时候需要先将老的环境变量导入进去然后在加上新的路径否则会出现你的路径直接覆盖掉之前环境变量PATH里面的所有路径的情况PATH里面的路径下的所有程序都被默认为是系统指令

在这里插入图片描述

在这里插入图片描述

4.
which指令在底层实现上实际就是从环境变量PATH下的路径当中搜索的帮助我们查找对应的指令路径如果我们的程序所在路径也被添加到了PATH中那么which也就可以查到我们所写的程序了。

在这里插入图片描述

5.
我们的环境变量是内存级的所以在你将自己的路径导入到环境变量PATH之后也只是暂时的等你退出xshell之后你的环境变量就又会恢复到默认的样子了

二、环境变量的深度理解

1.shell进程和环境变量的关系

1.
在我们登录shell的时候会默认让你当前的shell进程把对应的bash_profile里面的内容执行一次就是将环境变量导入到你当前的shell进程当中环境变量的配置就是通过它在启动的时候加载到bash当中的linux在环境变量的配置文件当中就有环境变量的设置当我们登录shell的时候这个环境变量就会load到当前的shell进程当中。

2.
shell做为一种和Linux系统的特殊交互式工具为用户提供了启动程序、管理文件系统中的文件及运行在Linux上的进程的途径。shell通过解析输入的文本命令在内核中执行来达到与系统交互的功能。shell包含了一组内部命令通过这些命令可以进行文件管理、程序管理及运行等操作。

3.
除了在文本命令界面上or虚拟控制器终端or终端仿真器通过命令行执行外可以通过将多个shell命令放入文件中作为程序执行这些文件就是shell脚本。在Linux系统中有许多不同类型的shell如ash、tsch、zsh等它们各自有不同的特性可以根据需求自行选择。通常Linux发行版本的默认shell都是bash shell由GNU项目开发的类Unix shell)。

4.
通常我们在执行shell命令的时候直观的感觉就是命令是直接运行在Linux系统上的其实这是个主观的误解shell本身就是个程序是运行在Linux上的进程shell命令的执行是在对应的进程内运行的

5.
当用户登入到虚拟终端or终端仿真器上时就会启动默认的shell程序。用户登入启动什么样的shell取决于在/etc/passwd用户配置文件中列出的用户默认shell。

6.
Linux系统本身也有一个默认的shell就是/bin/sh是用于在系统中启动系统shell脚本所指定的默认shell。通常在Linux系统中这个文件是一个符号链接文件指向/bin/bash这个shell也可以更改/bin/sh的链接来更换系统默认shell

7.
用户登入终端所启动的shell是一个父shell。在终端的提示符后输入bash命令或其他等效bash命令时会创建一个新的shell程序这个shell被称为子shell。如下我们在终端中输入两次bash命令后使用ps --forest查看进程嵌套关系可以看出父shell和子shell的关系

本文第三部分shell进程的部分内容转载自csdn博主ONLY_MIT的文章

2.环境变量的作用和Linux操作系统的准备工作

1.
无论是我们自己写的程序还是操作系统提前给我们准备好的程序想要运行都必须先加载到内存里面因为CPU只能从内存中读取代码和数据但是这里有一个潜在的问题这些程序想要运行都必须让操作系统先找到这些程序找到这些程序才能把他们加载到内存里面。

2.
操作系统要找这些程序就必须去特定的路径下面去找这些程序包括系统自带的指令程序和我们自己所写的程序操作系统还有可能找头文件找动态库静态库等等但是为什么你说操作系统能找到这些东西它就能一定找到呢操作系统如何找到这些东西啊

3.
其实想要找到这些东西操作系统需要做很多的准备工作才能像我们所说的那样轻松想要找什么东西就把那个东西找到了所以操作系统在启动的时候他就已经默认从配置文件当中读取了他自己曾经把软件安装到了哪些路径下他把安装到哪些路径下这些重要信息都记录在配置文件里面等到OS启动的时候把配置文件中的这些信息导入到内存里面构建出一个内存级变量这种变量就是环境变量上面所讲的PATH环境变量就是操作系统在启动命令行解释器shell的时候将PATH这样的变量导入到shell的上下文当中当我们执行对应的指令的时候我们就必须通过PATH环境变量里面指定的默认的搜索路径去查找对应的可执行程序所以操作系统为了让我们找到可执行程序其实做了很多的准备工作帮我们定义了许许多多的环境变量通过环境变量帮助我们做了很多本身我们看不见的工作除PATH这个环境变量其实还有很多很多的其他环境变量操作系统需要完成其他很多我们忽略掉的工作这就需要依靠这些它自己定义出来的环境变量这些环境变量都有不同的用途配色方案当前路径主机名用户名历史指令记录默认的shell类型这些都要依靠OS他自己定义出来的环境变量去隐式的解决或处理我们看不到的问题和工作。

在这里插入图片描述

4.
在不同的使用场景下要求操作系统在启动shell之后给我们做命令行解释的时候必须预先设置好一批未来shell可能用到的变量通过这些变量完成我们输入的命令的解释所以操作系统为了满足不同的应用场景必须预先在自己的OS内设置一大批的全局变量这些全局变量其实就是环境变量

3.测试环境变量USER

1.
su - 其实是让root重新登录这时候就会以root的身份重新加载很多的东西把root相关的环境变量全部加载到shell的上下文当中su仅仅是将身份切换一下但是当前的路径是没有变化的。

2.
可以看到环境变量USER会随着我们身份的切换不断的更新它的变量值这也正是USER环境变量所能起到的作用。

在这里插入图片描述

4.测试环境变量HOME

1.
HOME环境变量记录当前用户的工作目录在具体的哪个路径。

在这里插入图片描述
2.
cd的本质其实就是shell在解析指令时看到了波浪号shell就会直接调用环境变量HOME的值

在这里插入图片描述

三、环境变量和本地变量的关系本地变量包含环境变量

1.shell子进程会继承环境变量

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define USER "USER"
  5 #define MY_ENV "myval"
  6 
  7 
  8 int main()
  9 {
 10     char*myenv=getenv(MY_ENV);
 11     if(NULL == myenv)
 12     {
 13         printf("%s: not found\n",MY_ENV);
 14         return 1;
 15     }
 16     printf("%s=%s\n",MY_ENV,myenv);
 17                                                                                                                                                                      
 18     return 0;
 19 }  

1.
父进程shell定义的本地变量不会被子进程继承下去但是父进程的环境变量是会被子进程继承下去的继承的原因就是为了满足不同的应用场景因为许多系统指令ls、whoami、pwd、which、su - 都会涉及到使用环境变量所以这些指令子进程必须继承父进程bash的环境变量以满足不同的使用场景。
所以环境变量是具有全局性的因为无论是父进程还是子进程都有环境变量子进程的环境变量是从父进程继承得来的。

2.
本地变量只会在当前进程bash内部有效因为它不会被继承下去具有局部性。

在这里插入图片描述

2.显示本地变量和环境变量的指令

1.
set指令可以显示shell中的环境变量和非环境变量

在这里插入图片描述
2.
set显示出来的变量巨多因为shell本地变量包括了环境变量

下面的本地变量>就是指令续行时候的提示符
在这里插入图片描述
在这里插入图片描述

3.env可以显示所有的环境变量

在这里插入图片描述

3.导环境变量+取消本地变量

export MYVAL="youcanseeme"
unset MYVAL

1.
导入环境变量可以先在命令行定义本地变量然后导成环境变量也可以两个步骤同时进行取消环境变量或本地变量可以通过unset指令来操作。

在这里插入图片描述
2.
由于自己定义的环境变量默认就是字符串所以在定义的时候既可以带上双引号也可以不带双引号但如果出现定义的环境变量带空格的话就必须带上双引号了所以还是建议在定义的时候带上空格

4.为什么ls显示文件的时候不用带./呢shell会维护环境变量

1.
shell会维护环境变量的值就比如我们会不停的切换路径那么环境变量PWD的值就会随时被shell更改为当前路径所以ls在作为子进程运行的时候继承PWD的值之后ls就可以理所应当的显示出来当前的路径是在哪里。

2.
下面我们也可以自己用C语言程序的运行来获取当前路径利用shell实时维护环境变量PWD的特性来完成。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define USER "USER"
  5 #define MY_ENV "myval"
  6 #define MYPWD "PWD"
  7 
  8 int main()
  9 {
 10     printf("%s\n",getenv(MYPWD));
 11 }   

5.环境变量的配置文件详谈

在这里插入图片描述
转载自csdn博主吃鱼的羊文章

四、命令行参数表和环境变量表

1.命令行参数表

1.
在main函数中实际上有隐藏的参数只不过我们平常不使用这些参数因为我们平常用不着在系统编程中使用这些参数是比较常见的并且main会被一个叫START_UP的函数调用START_UP函数在你的程序加载到内存的时候被操作系统调用参数实际上就是我们的命令行解释器bash也就是父进程传递的我们只需要在命令行上写指令就可以了shell在解释我们的指令时就会给main函数传参了。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define USER "USER"
  5 #define MY_ENV "myval"
  6 #define MYPWD "PWD"
  7 #include <unistd.h>
  8 
  9 
 10 
 11 int main(int argc ,char* argv[])
 12 {
 13 
 14     for(int i=0;i<argc;i++)
 15     {
 16         printf("argv[%d]->%s\n",i,argv[i]);
 17     }
 18 
 19 }    

2.
在命令行中运行程序的时候实际上可以添加命令行参数shell在解释这些指令的时候就会给main函数传参

在这里插入图片描述
3.
main函数中的第一个参数是命令行中运行程序的时候字符串的个数以空格为分隔符比如上面运行时-a -b -c等实际上是三个字符串./mycmd也是一个字符串所以argc代表的就是字符串的个数argv指针数组中的指针指向的就是这些字符串通过程序运行结果和代码可以证明这个结论argv数组中打印出来的值实际上就是这些字符串所以main函数中的第二个参数就是命令行参数表表中的指针指向命令行中的所有字符串。

在这里插入图片描述

那么他有什么意义呢

4.
系统指令其实就是C语言写的程序那么它在带指令运行的时候也能实现不同的功能这是怎么做到的呢实际上在实现的代码中的main函数就是需要argc、argv这样的参数实现的

在这里插入图片描述

下面我们就通俗的实现一个不同选项拥有不同功能的进程。

int main(int argc ,char* argv[])
   12 {
   13 
   14     if(strcmp("-a",argv[1]) == 0)
   15     {
   16         printf("功能a\n");
   17     }                            
   18      
   19     if(strcmp("-b",argv[1]) == 0)
   20     {
   21         printf("功能b\n");
   22     }                            
   23     if(strcmp("-c",argv[1]) == 0)
   24     {                     
   25         printf("功能c\n");
   26     }                            
   27      
   28     if(strcmp("-ac",argv[1]) == 0)
   29     {
   30         printf("功能ac\n");
   31     }                             
   32     if(strcmp("-bc",argv[1]) == 0)
   33     {                      
   34         printf("功能bc\n");                                                                                                                                                          
   35     }                             
   36     if(strcmp("-ab",argv[1]) == 0)
   37     {
   38         printf("功能ab\n");
   39     }                             
   40     if(strcmp("-abc",argv[1]) == 0)
   41     {                      
   42         printf("功能abc\n");
   43     }                              
   44 }

在这里插入图片描述
5.所以命令行参数最大的意义就是通过不同的参数也就是执行时携带的选项使得进程拥有不同的功能

6.
在windows下的命令提示符当中我们也可以通过不同的命令行参数来使得进程实现不同的功能例如下面的关机指令可以设置关机时间也可以取消关机选择关机通过-t、-a、-s等参数实现。

在这里插入图片描述

2.子进程中三种获取环境变量的方式

2.1 通过系统调用获取环境变量获取指定的环境变量内容

1.
通过getenv( )系统调用就可以获得环境变量USER的值是什么

 1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <string.h>
    4 #define USER "USER"
    5 
    6 
    7 
    8 int main()
    9 {
W> 10     char*who = getenv(USER);
   11     printf("USER:%s\n",who);                                                                                                                                       
   12     return 0;                                                                                                               
   13 }

在这里插入图片描述

2.
sudo的本质其实就是将环境变量USER由普通用户改成root用户这时候某些不允许普通用户所做的行为通过root用户的身份就可以做了。

下面代码以通俗的方式解释了我们平常以普通身份进行某些操作时遇到的权限拒绝的原理其实在真正的过程当中是需要用到getenv()和一些文件属性获取的系统调用stat()通过这些系统调用来查看你是否拥有对应操作的权限。

3.stat获取文件属性这一系统调用接口后面的博文会详细讲解。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #define USER "USER"
  5 
  6 
  7 
  8 int main()
  9 {
 10     char*who = getenv(USER);
 11     if(strcmp(who,"root")==0)
 12     {
 13         printf("USER:%s\n",who);
 14 
 15     }
 16     else
 17     {                                                                                                                                                                
 18         printf("permission denied!\n");
 19     }
 20 
 21     return 0;
 22 }

2.2 环境变量表获取所有的环境变量名和内容

W> 11 int main(int argc ,char* argv[],char* env[])
   12 {
   13 
   14     for(int i=0; env[i]; i++)
   15     {
   16         printf("env[%d]-->%s\n",i,env[i]);                                                                                                         
   17     }
   18 
   19 }

1.
可以看到通过main函数的第三个参数子进程也可以获得所有的环境变量。这也是子进程继承shell环境变量的一种方式。

在这里插入图片描述

2.
每个进程都会被shell传一个环境表环境表是一个字符指针数组每个指针指向一个以斜杠0结尾的环境变量字符串

2.3 第三方指针变量environ获取所有的环境变量名和内容

1.
C语言默认提供了一个第三方指针变量叫做environ在调用main的时候实际上系统就把environ这个变量作为main的第三个参数传给main函数了这里涉及到C语言中数组传参的问题environ就相当于指针数组env[ ]的另一个数组名environ指向的就是env数组的第一个元素根据数组名代表首元素地址可知environ其实就是env的另一个数组名。

在这里插入图片描述
2.
environ是在编译好c或c++程序之后系统默认初始化好的一个全局的二级指针指向env数组的第一个元素因为environ[ i ]=*( environ + i )所以另一种获取环境变量的方式如下

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>                                                                                                                                  
  4                    
  5                       
  6 int main()         
  7 {                  
  8  
  9     extern char** environ;
 10     for(int i=0; environ[i]; i++)
 11     {                            
 12         printf("environ[%d]-->%s\n",i,environ[i]);
 13     }                                             
 14                                  
 15 }   

在这里插入图片描述

五、通过系统调用更改或增加环境变量

前面是通过命令行式的export指令来增加环境变量我们也可以通过系统调用putenv()来更改或增加环境变量这个系统调用放到后面的博文来进行详细的讲解。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: shelllinux

“【Linux】Linux环境变量的理解 --- 命令行参数、shell子进程、环境、本地变量…” 的相关文章