Linux:Shell环境变量与下令行参数

打印 上一主题 下一主题

主题 862|帖子 862|积分 2586

目录
Shell的变量功能
什么是变量
变数的可变性与方便性
影响bash环境操纵的变量
脚本步伐计划(shell script)的好帮忙
变量的使用:echo
变量的使用:HOME 
环境变量相干下令
获取环境变量 
环境变量和本地变量 
下令行参数 
什么是下令行参数
下令行参数有什么用 
环境变量与下令行参数 


Shell的变量功能

           变量是 bash 环境中非常告急的一个玩意儿,我们知道 Linux 是多人多任务的环境,每个人登录体系都能取得一个 bash shell, 每个人都能够使用 bash 执行 mail 这个下令来吸收『本身』的邮件等。题目是,bash是如何得知你的邮箱是哪一个文件?这就必要变量的资助。所以,你说变量告急不告急?下面我将介绍告急的环境变量、变量的使用与设置等数据。   什么是变量

           那么,什么是『变量』呢?简朴的说,就是让某一个特定字符串代表不固定的内容就是了。举个大家在中学都会学到的数学例子, 那就是:『 y = ax + b 』这东西,在等号左边的  (y)  就是变量,在等号右边的(ax+b)  就是变量内容。 要留意的是,左边是未知数,右边是已知数喔! 讲的更简朴一点,我们可以『用一个简朴的 "  字眼  "   来代替另一个比较复杂大概是轻易变更的数据』。这有什么好处啊?最大的好处就是『方便!』。   变数的可变性与方便性

           举例来说,我们每个账号的邮件信箱预设是以 MAIL   这个变量来进行存取的, 当   dmtsai   这个使用者登入时,他便会取得 MAIL   这个变量,而这个变量的内容实在就是   /var/spool/mail/dmtsai  , 那如果vbird 登入呢?他取得的   MAIL   这个变量的内容实在就是   /var/spool/mail/vbird   。 而我们使用信件读取指令 mail   来读取本身的邮件信箱时,这支步伐可以直接读取   MAIL   这个变量的内容, 就能够自动的分辨出属于本身的信箱信件啰!这样一来,计划步伐的步伐员就真的很方便!   

             如上图所示,由于体系已经帮我们规划好 MAIL    这个变量,所以用户只要知道    mail    这个指令如何使用即可, mail    会主动的取用    MAIL    这个变量,就能够如上图所示的取得本身的邮件信箱了!   (   留意大小写,小写的 mail    是指令, 大写的    MAIL    则是变量名称喔!   )                   那么使用变量真的比较好吗?这是固然的!想象一个例子,如果 mail     这个指令将     root     收信的邮件信箱(mailbox) 档名为     /var/spool/mail/root     直接写入步伐代码中。那么当     dmtsai     要使用     mail     时,将会取得 /var/spool/mail/root     这个档案的内容! 不合理吧!所以你就必要帮     dmtsai     也计划一个     mail     的步伐,将 /var/spool/mail/dmtsai     写死到     mail     的步伐代码当中! 天吶!那体系要有多少个     mail     指令啊?反过来说,使用变量就变的很简朴了!由于你不必要更动到步伐代码啊! 只要将 MAIL     这个变量带入差异的内容即可让所有使用者透过 mail     取得本身的信件!固然简朴多了!          影响bash环境操纵的变量

           某些特定变量会影响到 bash   的环境!举例来说,我们前面已经提到过许多次的那个   PATH   变量! 你能不能在任何目录下执行某个指令,与 PATH   这个变量有很大的关系。比方你下达   ls 这个指令时,体系就是透过 PATH 这个变量里面的内容所记录的路径顺序来搜寻指令的呢!如果在搜寻完 PATH 变量内的路径还找不到 ls 这个指令时, 就会在屏幕上表现『 command not found 』的错误信息。               如果说的专业一点,那么由于在 Linux System    下面,所有的线程都是必要一个执行码, 而就犹如上面提到的,你『真正以 shell    来跟 Linux 沟通,是在正确的登入 Linux    之后!』这个时候你就有一个 bash 的执行步伐,也才可以真正的经由    bash    来跟体系沟通!而在进入    shell    之前,也正犹如上面提到的,由于体系必要一些变量来提供他数据的读写 (大概是一些环境的设置参数值,比方是否要表现彩色等) ,所以就有一些所谓的   『环境变量』 必要来读入体系中了!这些环境变量比方    PATH、HOME、MAIL、SHELL 等等,都是很告急的, 为了区别与自定义变量的差异,环境变量通常以大写字符来表示!    脚本步伐计划(shell script)的好帮忙

                 这些还都只是体系默认的变量的目的,如果是个人的设定方面的应用呢:比方你要写一个大型的 script 时,有些数据由于大概由于用户习惯的差异而有差异,比如说路径好了,由于该路径在 script     被使用在相称多的地方,如果下次换了一部主机,都要修改 script     里面的所有路径,那么我一定会疯掉! 这个时候如果使用变量,而将该变量的定义写在最前面,后面相干的路径名称都以变量来代替, 嘿嘿!那么你只要修改一行就等于修改整篇 script     了!方便的很!所以,良好的步伐计划师都会善用变量的定义!         

                 末了我们就简朴的对『什么是变量』作个简朴定义好了: 『变量就是以一组笔墨或符号等,来代替一些设定大概是一串保留的数据!』, 比方:我设定了『myname』就是『     VBird     』,所以当你读取 myname 这个变量的时候,体系自然就会知道!那就是      VBird      ! 那么如何『表现变量』呢?这就必要使用到 echo      这个指令!                           说的口沫横飞的,也不知道『变量』与『变量代表的内容』有啥关系? 那我们就将『变量』的『内容』拿出来给您看看。你可以使用 echo 这个指令来取用变量, 但是,变量在被取用时,前面必须要加上钱字号『 $       』才行,举例来说,要知道       PATH       的内容,该如何是好?               变量的使用:echo

                  我们这里单纯是拿        echo        来读出变量的内容而已,更多的 echo        使用,执行指令       man echo 吧       !                       
  1. [root@www ~]# echo $variable
  2. [root@www ~]# echo $PATH
  3. /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
  4. [root@www ~]# echo ${PATH}
  5. ----------------------------------------------------------------------
  6. [root@www ~]# echo $myname
  7.              <==这里幵没有任何数据~因为这个变量尚未被设置!是空的!
  8. [root@www ~]# myname=VBird
  9. [root@www ~]# echo $myname
  10. VBird        <==出现了!因为这个发量已经被设定了!
复制代码
             若该变量必要扩增变量内容时,则可用 "$变量名称" 戒 ${变量} 累加内容,如下所示:
  1. 『PATH="$PATH":/home/bin』
复制代码
我们知道执行一个步伐时,是必要./mytest 的,但下面这样设置之后,直接mytest,不用带 ./ ,当前路径该步伐就可以直接运行。
  

  • 方法 1:把 proc 拷贝到环境变量 PATH 指定的任一路径下。
  • 方法 2:把 proc 所在路径添加到环境变量 PATH 中。(留意:本身添加的环境变量,体系重启后是不会被保存的)
  1. $ PATH=$PATH:/home/ll/xxx/10
  2. # :冒号是分隔符
  3. # 注意:PATH=/home/ll/xxx/10,不能这样写,必须加上$符号,否则会把PATH中所有内容覆盖掉
复制代码
 效果图:

  
  变量的使用:HOME 

        分别在 root 和平凡用户下执行 cd ~ 和 pwd 查看家目录,分别是 /root 和 /home/test,为什么得到的结果不一样呢?由于差异用户的家目录中的设置文件不一样,所以差异用户下的环境变量 HOME 也是不一样的。
  1. [root@VM-0-12-centos ~]$ echo $HOME
  2. /root
  3. [test@VM-0-12-centos ~]$ echo $HOME # 指定用户的主工作目录
  4. /home/test
复制代码
环境变量相干下令


  • echo:表现某个环境变量值。
  • export:设置一个新的环境变量。
  • env:表现所有环境变量。
  • unset:清除环境变量。
  • set:表现本地定义的 shell 变量和环境变量。
获取环境变量 

getenv 和 setenv 函数介绍:
  1. #include <stdlib.h>
  2. char *getenv(const char *name); // 获取环境变量
  3. int setenv(const char *name, const char *value, int overwrite); // 更改或添加环境变量
  4. name:环境变量的名称
  5. 返回值:环境变量的内容
复制代码
  1. // proc.c
  2. #include <stdio.h>
  3. #include <stdlib.h> // getenv
  4. int main()
  5. {
  6.     printf("%s\n", getenv("PATH"));
  7.     printf("%s\n", getenv("HOME"));
  8.     printf("%s\n", getenv("SHELL"));
  9.     return 0;
  10. }
复制代码

代码通过 getenv 函数读取了 PATH、HOME、SHELL 等环境变量。这些变量的值继承自父进程(即启动该步伐的进程)。


  • 在下令行运行 ./proc.c 时,父进程是 bash
  • bash 在启动时会加载本身的环境变量(比方从 ~/.bashrc),并在创建子进程(你的步伐)时将这些变量转达给子进程。
当你在 bash 中输入下令时(如 ls 或 ./a.out),bash 的典范行为是:

  • fork():创建一个子进程(复制父进程 bash 的环境变量、内存状态等)。
  • exec():在子进程中替换为新的步伐(如 ls 或 ./a.out)。
  • 环境变量继承:子进程通过继承机制得到父进程(bash)的环境变量。
因此,你的步伐中通过 getenv 读取到的环境变量,实际上是父进程 bash 转达下来的。那么就很好的引出了环境变量和本地变量的区别,具体请看如下。
环境变量和本地变量 

环境变量(环境变量通常具有全局属性:可以被子进程继承下去)。环境变量实际上是在当前 bash 的上下文中定义的。所以在当前下令行表明器 bash 内可以被访问到,在 bash 创建的子进程内也可以被访问到。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5.     char* env = getenv("MYENV");
  6.     if(env)
  7.     {
  8.         printf("%s\n", env);
  9.     }
  10.     return 0;
  11. }
复制代码
直接运行发现没有结果,阐明该环境变量根本不存在。


  • 导出环境变量:export MYENV="hello world"
  • 再次运行步伐,发现有结果了。阐明:环境变量是可以被子进程继承下去的。
本地变量(只能在当前 shell 下令行表明器内被访问,不可以被子进程继承)
  1. [ll@VM-0-12-centos 10]$ MY_VAL="hello world"  # 定义本地变量(在bash内定义的)
复制代码
 如何查看本地变量呢?
  1. [ll@VM-0-12-centos 10]$ echo $MY_VAL  # 在当前命令行解释器bash内访问本地变量
  2. hello world
复制代码
如何证明本地变量不能被子进程继承? 
  1. // proc.c
  2. #include <stdio.h>
  3. #include <stdlib.h> // getenv
  4. int main()
  5. {
  6.     printf("%s\n", getenv("MY_VAL"));
  7.     return 0;
  8. }
复制代码

该怎么解决这个题目呢?可以将本地变量 MY_VAL 设置成环境变量。
  1. [ll@VM-0-12-centos 10]$ exprot MY_VAL  # 把本地变量MY_VAL导出成环境变量
复制代码

上面说到,我们在下令行上运行的大部门下令,都是 bash 创建子进程来执行的,而本地变量不能被子进程继承,那为什么使用 echo 下令,却可以访问本地变量呢? 

在Linux中的下令分类:
  1. # 将PATH变量设置为空
  2. [test@VM-16-11-centos ~]$ export PATH=""
  3. # 以下命令均不能使用
  4. [test@VM-16-11-centos ~]$ ll
  5. -bash: ls: No such file or directory
  6. [test@VM-16-11-centos ~]$ touch
  7. -bash: touch: No such file or directory
  8. [test@VM-16-11-centos ~]$ mkdir
  9. -bash: mkdir: No such file or directory
  10. # pwd仍然可以使用
  11. [test@VM-16-11-centos ~]$ pwd
  12. /home/test
复制代码


  • 通例下令:shell通过fork让子进程执行的
  • 内建下令:shell下令行的一个函数,可以直接读取shell内部定义的本地变量
而在上面的测试中,像ls,mkdir这样的下令,都是shell通过fork创建子进程来执行的,而这里的PATH路径已经被用户粉碎了,因此找不到搜索的路径,因此找不见是固然的事,但是为什么pwd可以找到?这是由于pwd这样的下令是内建下令,这是shell下令行的一个函数,可以直接读取shell内部的本地变量,因此就可以找到对应的值进行输出了。
会提供一个environ指针,这个指针会指向一张环境表,环境表是一个字符指针数组,每一个指针都会有一个字符串。

下令行参数 

什么是下令行参数

在学习C语言中,对于main函数当初的写法是没有任何参数的,但是实际上,main函数是可以有参数的,比如下面的写法:
  1. #include <stdio.h>
  2. int main(int argc, char* argv[])
  3. {
  4.         int i = 0;
  5.         for (i = 0; i < argc; i++)
  6.         {
  7.                 printf("%d:%s\n", i, argv[i]);
  8.         }
  9.         return 0;
  10. }
复制代码
运行结果:
  1. [test@VM-16-11-centos 10_15]$ vim myproc.c
  2. [test@VM-16-11-centos 10_15]$ make
  3. gcc -o myproc myproc.c
  4. [test@VM-16-11-centos 10_15]$ ./myproc
  5. 0:./myproc
复制代码
实在,下令行参数是用来支持各种指令级别的下令行选项的设置,比方这里的argv数组中,存储的字符串实在就是用户写的下令,而如果现在我在运行步伐的时候带上选项 :
  1. [test@VM-16-11-centos 10_15]$ ./myproc -a -b -c -d
  2. 0:./myproc
  3. 1:-a
  4. 2:-b
  5. 3:-c
  6. 4:-d
复制代码
所以推出: 
  1. int main(int argc, char *argv[]) {
  2.     // argc 表示参数总数(包括程序名本身)
  3.     // argv[0] 是程序名,argv[1] 是第一个参数,依此类推
  4. }
复制代码

        并且运行结果发现打印的信息就是以用户写的指令开始进行分割,然后把信息放到数组中,从中实在看出,用户在运行步伐的时候写的下令大概是带的选项都可以被main函数读取并且传参,函数体内部就可以使用这个机制实现差异的选项带来的结果。比如,Linux中有ls下令,用来查看文件夹中的内容,如果使用的是ls -a大概是ls -l这些选项,就会产生差异的结果,实际上这样的结果也是通过这个原理,通过读取argv数组中的内容就可以实现各种目的。 
示例:ls 下令的选项实现逻辑
  1. // 伪代码示意
  2. #include<stdio.h>
  3. #define SHOW_HIDDEN (1 << 0) // 二进制 0b01
  4. #define LONG_FORMAT (1 << 1) // 二进制 0b10
  5. int main(int argc, char *argv[]) {
  6.     int options = 0; // 初始化选项标志位
  7.     for (int i = 1; i < argc; i++) {
  8.         if (strcmp(argv[i], "-a") == 0) {
  9.             options |= SHOW_HIDDEN; // 设置显示隐藏文件标志
  10.         } else if (strcmp(argv[i], "-l") == 0) {
  11.             options |= LONG_FORMAT; // 设置长格式输出标志
  12.         }
  13.     }
  14.     // 根据 options 执行相应逻辑
  15.     list_directory(".", options);
  16.     return 0;
  17. }
复制代码
  1. $ ./program
  2. 运行结果:file1.txt  file2.txt  dir1
  3. $ ./program -a
  4. 运行结果:.  ..  .hidden_file  file1.txt  file2.txt  dir1
  5. $ ./program -l
  6. 运行结果:
  7. -rw-r--r-- 1 user group  1024 Jan 1 10:00 file1.txt
  8. drwxr-xr-x 2 user group  4096 Jan 1 10:00 dir1
  9. $ ./program -a -l
  10. 运行结果:
  11. drwxr-xr-x 2 user group  4096 Jan 1 10:00 .
  12. drwxr-xr-x 5 user group  4096 Jan 1 10:00 ..
  13. -rw-r--r-- 1 user group     0 Jan 1 10:00 .hidden_file
  14. -rw-r--r-- 1 user group  1024 Jan 1 10:00 file1.txt
  15. drwxr-xr-x 2 user group  4096 Jan 1 10:00 dir1
  16. $ ./program -x
  17. 运行结果:
  18. file1.txt  file2.txt  dir1
复制代码


  • 无参数:默认行为(不表现隐蔽文件,短格式)。
  • -a:表现隐蔽文件。
  • -l:长格式表现文件元数据。
  • -a -l:同时启用两种模式。
  • 无效参数:被忽略,按默认模式运行。
下令行参数有什么用 

为什么要存在下令行参数呢?
资助我们能够给同一个步伐,计划出差异的业务功能。
   举个小例子,比如我想要实现这样一个盘算器:
如果输入 ./cal,则会提示该步伐的正确用法:Usage:./cal -[a|s] x y;
  输入 ./cal -a 1 2,cal 步伐可以输出 1 + 2 的结果;
  输入 ./cal -s 4 2,cal 步伐可以输出 4 - 2 的结果。
  1. #include <stdio.h>
  2. #include <stdlib.h> // atoi -- 函数原型:int atoi(const char *nptr); // 将C字符串转换成整数
  3. #include <string.h> // strcmp
  4. // cal命令的用法手册
  5. void Usage(const char* cal)
  6. {
  7.     printf("Usage: %s -[a|s] x y\n", cal);
  8. }
  9. int main(int argc, char* argv[]) // 接收命令行参数
  10. {
  11.     // 输入的参数个数不为4
  12.     if (argc != 4)
  13.     {
  14.         Usage(argv[0]);
  15.         return 1; // 退出程序
  16.     }
  17.     // 保存第3个和第4个参数                                                      
  18.     int x = atoi(argv[2]);
  19.     int y = atoi(argv[3]);
  20.    
  21.     // 根据不同参数,执行不同功能,然后输出结果
  22.     if (strcmp(argv[1], "-a") == 0)
  23.     {                                            
  24.         printf("%d + %d = %d\n", x, y, x + y);
  25.     }
  26.     else if (strcmp(argv[1], "-s") == 0)
  27.     {
  28.         printf("%d - %d = %d\n", x, y, x - y);
  29.     }
  30.     else
  31.     {
  32.         Usage(argv[0]);
  33.         return 1; // 退出程序
  34.     }
  35.     return 0;
  36. }
复制代码
运行结果: 
  1. [test@VM-0-12-centos 10]$ ./cal        # 命令使用手册
  2. Usage: ./cal -[a|s] x y
  3. [test@VM-0-12-centos 10]$ ./cal -a 1 2 # 实现加法
  4. 1 + 2 = 3
  5. [test@VM-0-12-centos 10]$ ./cal -s 4 2 # 实现减法
  6. 4 - 2 = 2
复制代码
环境变量与下令行参数 

main 函数除了可以转达两个和下令行参数相干的参数 argc 和 argv 以外,还可以转达第 3 个参数 env
  1. int main(int argc, char* argv[], char* env[]);
复制代码
这也是 main 函数获取环境变量的方式。通过给 main 函数第三个参数传参,把一个个环境变量转达给当前步伐,当前步伐运行起来变成进程,就意味着当前这个进程获取到了这些环境变量。

每个被 bash 创建的子进程都会吸收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以 ’\0’ 结尾的环境字符串(环境变量)。
  1. // proc.c
  2. #include <stdio.h>
  3. #include <string.h>
  4. int main(int argc, char* argv[], char* env[]) // 通过第三个参数接收环境变量
  5. {
  6.     for (int i = 0; env[i]; i++) // 循环结束条件为env[i],遍历到NULL停止
  7.     {
  8.         printf("env[%d]: %s\n", i, env[i]); // 遍历字符指针数组env
  9.     }
  10.     return 0;
  11. }
复制代码
运行结果:获取到了当前 bash 内的所有环境变量。(由于环境变量被 bash 创建的子进程 proc 继承下去了)

所以现在知道 C 库函数 getenv 的实现原理了,比如 printf("%s\n", getenv("ATH"));,实在就是通过在字符指针数组 env 中进行字符匹配,找到 "ATH" 后面的内容并返回。 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天津储鑫盛钢材现货供应商

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表