一、初识命令行参数

1.1 介绍命令行参数
  1. 我们的main函数是可以接收参数的,而其中两个就是关于命令行参数的。一个是int类型的argc,它记录的是命令行参数的个数;一个是char类型的指针数组argv,它记录的就是命令行参数了,类型类型等价于char**,因为数组会退化成指针。

代码语言:javascript

AI代码解释

//这是一段c语言代码
  1 #include<stdio.h>
  2 
  3 int main(int argc, char *argv[])
  4 {
  5   printf("argc:%d\n", argc);
  6   int i = 0;                                                                                                                             
  7   for (; i < argc; i++)
  8   {
  9     printf("argv[%d]->%s\n", i, argv[i]);
 10   }
 11   return 0;
 12 }
  1. 我们在执行这个文件的时候,会输入一条指令,这条指令本质上也就是一个字符串,而shell会将我们的命令进行切割成一个一个的命令行参数形成一个参数列表后传给argv。我们所看到的argc/argv都是经过程序处理后所得到的。

在这里插入图片描述

在这里插入图片描述

  1. 运行这个程序可以看到,它的命令行参数个数有5个,分别是./test,a,b,c和d。这是因为shell将这串命令" ./test a b c d " 以空格符号为分界点进行切割形成一个个的命令行参数,形成参数列表之后传递给argv。
命令行参数组织方式

在这里插入图片描述

在这里插入图片描述

4. 指针数组argv的结构差不多是这样,里面存储的是一个个的字符串首地址,argv[0]到argv[4] / argv[argc - 1] 是5即argc个有效参数,而argv[5] / argv[argc] NULL是数组的结束标志。 5. 命令行参数个数argc>=1,不可能小于1。

1.2 为什么要有命令行参数?

现在展示一段代码:

代码语言:javascript

AI代码解释

  1 #include<stdio.h>
  2 #include<string.h>
  3 
  4 int main(int argc, char *argv[])
  5 {
  6   if (argc != 2)
  7   {
  8     printf("这个指令不是这样用滴,要这样用:%s -a|-b|-c|-d\n", argv[0]);
  9   }
 10   else if(!strcmp(argv[1], "-a"))
 11   {
 12     printf("执行该指令的第一个功能\n");
 13   }
 14   else if(!strcmp(argv[1], "-b"))
 15   {
 16     printf("执行该指令的第二个功能\n");
 17   }
 18   else if (!strcmp(argv[1], "-c"))                                                                                                       
 19   {
 20     printf("执行该指令的第三个功能\n");
 21   }
 22   else
 23   {
 24     printf("执行该指令的默认功能\n");
 25   }
 26 return 0;
 27 }

在这里插入图片描述

在这里插入图片描述

  1. 输入不同的命令之后便会呈现出不同的结果,这种用法是不是跟一些指令和指令的选项功能十分相似?比如ls,ls -l就是它的第一种功能,显示文件详细属性,ls -a就是第二种功能,能够显示隐藏文件。
  2. 命令行参数的本质应用,就是为了实现一个命令可以根据不同的选项从而实现不同的子功能。这是Linux里面几乎所有指令选项功能的实现方式。
  3. 来一个子问题:cat file.txt 这条指令是如何能够将file.txt的内容输出到显示屏的?cat是怎么做到的?这也是命令行参数的应用,cat能够通过argv拿到file.txt的名字,从而fopen打开文件之后再写入到显示器文件里面。从而我们就能看到文件里面的内容了。

二、环境变量

2.1 基本概念
  1. 环境变量是操作系统维护的键值对(KEY = VALUE)形式的全局配置信息。比如:我们在编写c/c++代码的时候,一些动静态库是如何链接的它们在哪里我们都是不知道的,而环境变量就存储了它们的地址,在链接的时候就可以通过这个地址找到它们。
  2. 环境变量具有全局性。至于为什么会有全局性接下来会讲到。
2.2 常见环境变量
PATH

在这里插入图片描述

在这里插入图片描述

  1. 首先根据path来了解一下环境变量的作用。在我们执行某个程序的时候,是必须要告诉操作系统这个程序的路径的,这是为了让操作系统知道它应该去哪里找目标程序,一个程序只有被OS找到了才能够被执行,相对路径和绝对路径都是可以的
  2. 像是ls,cat这样的指令其实也都是一个个的可执行二进制文件,而我们在使用这些指令的时候,却不需要告诉OS这个文件在哪里。这些可执行二进制文件都存放在/usr/bin/xxx里面,要执行这些指令的时候OS就会直接去这个路径下面去找。但是OS怎么会知道要去这里找呢?是由什么变量存储了这个地址吗?系统会去其他的路径下找文件吗?
  3. 有的,这是因为环境变量PATH的存在,这个PATH环境变量里已经存储好了一定量的系统路径(有多个),当我们执行一个没有路径的命令的时候,OS会根据这个PATH环境变量里面存储的路径一个一个去找,如果没有找到就会有提示行:command not found。
echo输出环境变量的值

在这里插入图片描述

在这里插入图片描述

  1. 我们可以用echo来输出环境变量的值,环境变量前面要加上,可以将其PATH理解为一个指针,而加上就是为了指针解引用拿到目标值(可以暂时这样理解,但实际不是这样)。可以看到,PATH这个环境变量里面存储了不止一个路径,这些不同的路径之间是通过 : 隔开的,在这些路径里面就能够看到存储了ls/cat文件的/usr/bin路径。
  2. 那么,如果我们在这个环境变量里面加上test(后面改名成test11,为了不跟系统的test文件重叠)文件的路径,是不是就可以不用告诉OS它在哪里了呢?是的。可以用export来实现:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  1. 完美符合猜想,不用指明路径就可以直接执行test11。还有一点,export的作用是重新导入一个环境变量到系统里面,通过 export PATH=$PATH:/新路径,所以我上面的命令是先把原来的 PATH 值和新路径拼接成一个新值,再通过 export 将这个 “拼接后的新 PATH” 作为环境变量导出,替换(覆盖)当前会话中原来的 PATH 环境变量。
  2. 也不用担心这种变换是永久的,退出重进会话时,PATH值就会恢复。
PWD

在这里插入图片描述

在这里插入图片描述

  1. 但如果将PATH彻底改掉,就不能直接使用ls,cat这样的指令了。但是某些指令比如pwd就还能够执行,这是像pwd这样的指令是Shell的内置命令,它是不依赖于PATH的,系统会维护一个叫做PWD的环境变量,使用pwd指令的时候,系统就会把PWD里面的值打印出来,但这个PWD环境变量并非pwd指令的唯一依赖。用env命令可以显示出所有的环境变量,就可以看到PWD了,也可以用echo。

在这里插入图片描述

在这里插入图片描述

env查看所有环境变量

在这里插入图片描述

在这里插入图片描述

HOME和SHELL
  1. HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)。
  2. SHELL:当前Shell,它的值通常是/bin/bash。
2.3 环境变量的组织方式和使用方法
组织方式

在这里插入图片描述

在这里插入图片描述

  1. 环境变量的组织方式与命令行参数类型,它也是一张表,也就是一个字符指针数组,里面存储着各个环境变量。
  2. 我们在写代码的时候,应该如何获取这些环境变量呢?—通过main函数的第三个参数或者是特定的函数比如getenv和environ。
使用main函数的第三个参数

代码语言:javascript

AI代码解释

//使用main函数的第三个参数
	4 int main(int argc, char* argv[], char* env[])
    5 {
    6   int cnt = 0;
    7   for(; env[cnt]; cnt++)
    8   {
    9     printf("env[%d]->%s\n", cnt, env[cnt]);                                                                                            
   10   }
   11   return 0;
   12 }
  • 必须要声明前面两个参数。
使用全局变量environ

代码语言:javascript

AI代码解释

int main()
 15 {
 16   extern char** environ;
 17   int cnt = 0;
 18   for (; environ[cnt]; cnt++)
 19   {
 20     printf("environ[%d]->%s\n", cnt, environ[cnt]);
 21   }
 22   return 0;
 23 }
  • 如果不想声明前两个参数的话,可以使用全局变量environ,它跟main函数第三个参数指向的是同一块地方,但是必须要进行声明entern char** environ。

在这里插入图片描述

在这里插入图片描述

使用函数getenv
  1. 使用main函数第三个环境变量和使用全局变量environ的结果一样。总之,我们使用跟打印命令行参数相同的方法同样也可以将环境变量都打印出来。但是我们在使用目标环境变量的时候肯定不是把所有的环境变量都给遍历一遍去找,所以这就得提到getenv函数了,这个函数可以用来找到目标环境变量。

在这里插入图片描述

在这里插入图片描述

  1. 通过man手册来了解一下这个getenv接口,使用这个接口需要包含头文件<stdlib.h>。接下来实验一下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.4 环境变量的全局属性
  1. 有没有想过一个问题,这些命令行参数和环境变量是谁给main函数的呢?—>是bash进程。命令行参数表和环境变量表都是存储在bash进程里面的,而进程是会被加载到内存里的,我们知道内存具有临时性,那么同时与bash进程一同加载到内存里的命令行参数表和环境变量表也都是具有临时性的,进程退出后内存释放,这些变量自动就会消失。那么这些具体的参数又是谁给bash的呢?是系统的配置文件。每当我们登录Linux系统时,bash进程就会去系统的配置文件里面去读取数据。退出系统再重新登录,之前用export修改的环境变量都会恢复原值,就是因为每次登录Linux系统启动bash进程,然后bash进程就去重新读取这些配置文件,而我们用exprot修改环境变量只是在修改内存里面的环境变量,不会改变系统的配置文件。
  2. 我们执行test进程,而test是bash的子进程,也就会共享bash的代码(父子进程会共享代码,以只读的形式)。而命令行参数和环境变量可以将它们理解为全局变量(目前可以这样理解,入门阶段),父子进程虽然会根据fork的返回值进行分流执行不同的代码,但是全局变量谁都可以用。而test里面创建出的子进程也会共享这份代码,即也可以使用命令行参数和环境变量。这也就是为什么环境变量具有全局性的原因。
  3. 我们来进行验证一下,会用到几个函数,分别是export用来导出环境变量,set用来显示本地变量和环境变量,unset用来清除环境和本地变量
  • 与环境变量对应的就是本地变量(Shell局部变量),格式:变量名 = 值。而用export导出的变量就会成为环境变量

set

在这里插入图片描述

在这里插入图片描述

export
  1. 设置一个环境变量A和一个本地变量B,然后在bash的子进程如test里面调用这两个变量来试试。

在这里插入图片描述

在这里插入图片描述

unset

在这里插入图片描述

在这里插入图片描述

  1. 这样就可以取消设置的本地变量和环境变量了,之后用set+grep筛选是看不到的。

代码语言:javascript

AI代码解释

#include<stdlib.h>
 32 int main()
 33 {
 34   printf("A:%s, B:%s\n",getenv("A"), getenv("B"));                                                                                       
 35   return 0;
 36 }

在这里插入图片描述

在这里插入图片描述

  1. 能够看到,只能够获取到bash里的环境变量A,不能获取到bash的本地变量。
2.5 命令总结
  1. echo:配合$可以用来打印任意变量(环境和本地变量都可以)。
  2. env:仅显示全部环境变量。
  3. set:显示本地变量、环境变量和Shell内置变量。
  4. unset:取消环境变量和本地变量。
  5. export:导出环境变量。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐