1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Linux环境变量和命令行参数

Linux环境变量和命令行参数

时间:2021-12-17 01:02:31

相关推荐

Linux环境变量和命令行参数

📒博客主页:Morning_Yang丶

🎉欢迎关注🔎点赞👍收藏⭐️留言

📌本文所属专栏: 【Linux】

🙏作者水平有限,如果发现错误,敬请指正!感谢感谢!

文章目录

1.1 基本概念1.2 查看环境变量1.3 环境变量:PATH1.4 环境变量:HOME1.5 和环境变量相关的命令1.6 通过 C 库函数获取环境变量:getenv1.7 环境变量 & 本地变量1.8 命令行参数① main 函数的参数列表② 命令行参数的意义③ 总结1.9 环境变量的组织方式① 前言② 通过 main 的第三个参数获取环境变量③ 通过全局变量 environ 获取环境变量(了解)

1.1 基本概念

环境变量我们早已听说过,比如在学习 Python 的时候,会在 windows 上配置环境变量:

可环境变量到底是什么呢

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

这些参数通常有特殊的用途。

比如:我们在编写 C/C++ 代码的时候,在链接的时候,我们从来不知道我们所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

环境变量通常具有某些特殊用途,环境变量在系统当中通常具有全局特性

常见环境变量

PATH:(当前用户)指定命令的搜索路径

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

SHELL:当前 shell,即当前用户使用的命令行解释器的版本,它的值通常是 /bin/bash。

HISTSIZE:命令历史记录保存数量。(centos 6.7 默认是 3000 条)

命令 history 可以查看所有命令历史记录。搭配管道history | wc -l可以查看命令历史记录的行数。

1.2 查看环境变量

echo $PATH命令,PATH 是环境变量的名称,查看指定环境变量。

env 命令,查看系统中所有的环境变量。

1.3 环境变量:PATH

思考

我们编写的 C/C++ 代码,编译生成的可执行程序,是不是一个命令呢?—— 是的。在 Linux 中,任何一个可执行程序,具有可执行权限(x),就称之为它是一条命令。所以我们通过gcc编译得到的可执行文件其实也是一条命令。

其实我们听过的:程序、命令、指令、可执行程序等等,其实都是一个概念,是同一个东西。(⭐)

思考

既然是同一个概念,那为什么我们运行ls等命令,不用带./当前路径,而运行我们自己的可执行程序proc必须要带./proc当前路径呢?

分析

环境变量 PATH 中保存的是指定命令的搜索路径

因为ls等命令是在系统的特定路径下保存起来的。

而我们的proc命令没有保存在 PATH 指定的这些路径中,而系统执行命令只会在 PATH 指定的这些路径中搜索,所以系统找不到我们的proc命令,就报错了。

每个路径都是绝对路径,并且每条路径以冒号 :分隔开,当我们运行一条命令时,如果在这些路径中都没查找到该命令,就会报错

思考

那有没有什么办法,可以让可执行程序proc不用带./当前路径就可以直接运行呢?

方法1:把proc文件拷贝到环境变量 PATH 指定的任一路径下。不推荐该方式,会污染别人写好的指令集。

方法2:把proc所在路径添加到环境变量 PATH 中。(注意:我们自己添加的环境变量,系统重启后不会被保存)

PATH=$PATH:/home/yzy/xxx/10# :冒号是分隔符# 注意:PATH=/home/yzy/xxx/10,不能这样写,必须加上$PATH:,否则会把PATH中所有内容覆盖掉

运行效果图:

注意

如果我们不幸把环境变量给覆盖掉了,不用担心,环境变量既然是变量,说明它是可以被赋值的,即在用户登录的时候,通过用户目录下的配置文件赋值的,所以只需要重新登录下就好了。

比如:用户目录下的 .bash_profile 文件,这些文件不建议自己去随意修改:

1.4 环境变量:HOME

分别在 root 和普通用户下执行 cd ~ 和 pwd 查看家目录,分别是/root/home/yzy,为什么不一样呢?

是因为不同用户的家目录中的配置文件不一样,所以不同用户下的环境变量 HOME 也是不一样的:

[yzy@VM-4-4-centos ~]$ echo $HOME # 指定用户的主工作目录/home/yzy[root@VM-4-4-centos ~]$ echo $HOME/root

1.5 和环境变量相关的命令

echo:显示某个环境变量值。export:设置一个新的环境变量。env:显示所有环境变量。set:显示在本地 shell 内定义的变量和环境变量。(既能查看本地变量,也可以查看环境变量)unset:清除环境变量。

1.6 通过 C 库函数获取环境变量:getenv

getenv 和 setenv 函数介绍:

#include <stdlib.h>/** name: 环境变量的名称* 返回值: 环境变量的内容*/char *getenv(const char *name); // 获取环境变量int setenv(const char *name, const char *value, int overwrite); // 更改或添加环境变量

👉 getenv 使用举例:

/* proc.c */#include<stdio.h>#include<stdlib.h> // getenvint main(){printf("%s\n", getenv("PATH"));printf("%s\n", getenv("HOME"));printf("%s\n", getenv("SHELL"));return 0;}

运行结果:在 bash 创建的子进程proc中成功获取到了环境变量。

结论

我们在命令行上运行的大部分命令,它们的父进程都是 bash。bash 创建子进程,然后由子进程执行用户输入的命令。

1.7 环境变量 & 本地变量

在命令行中,我们通常可以定义两种变量:

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

环境变量实际上是在当前 bash 的上下文中定义的。

所以在当前命令行解释器 bash 内可以被访问到,在 bash 创建的子进程内也可以被访问到。

本地变量(只能在当前 shell 命令行解释器内被访问,不可以被子进程继承)

[yzy@VM-4-4-centos day8]$ MY_VAL="hello world" # 定义本地变量(在bash内定义的)

如何查看本地变量呢?和查看环境变量方式一样:

[yzy@VM-4-4-centos day8]$ echo $MY_VAL # 在当前命令行解释器bash内访问本地变量hello world

👉 思考:如何证明本地变量不能被子进程继承

/* proc.c */#include<stdio.h>#include<stdlib.h> // getenvint main(){printf("%s\n", getenv("MY_VAL"));return 0;}

运行结果:段错误。

分析:

当我们输入./myproc后,bash 会创建子进程来执行myproc程序,但因为本地变量MY_VAL只能在当前 bash 内被访问,不能被其子进程继承,所以子进程中的getenv("MY_VAL")函数获取不到本地变量MY_VAL,导致程序报错。

那该怎么办呢?—— 我们可以将本地变量MY_VAL设置成环境变量。

[yzy@VM-4-4-centos day8]$ exprot MY_VAL # 把本地变量MY_VAL导出成环境变量

导入成功:

再次运行程序:就能成功访问到环境变量MY_VAL

👉思考

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

1.8 命令行参数

① main 函数的参数列表

思考:main 函数可以带参数吗?能带几个参数呢?—— 可以带参,但大部分都是缺省。

👉 举个例子:

/** argc: 命令行参数的个数* argv: 字符指针数组(指向各个命令行参数的字符指针所构成的数组)*/int main(int argc, char* argv[]) // 接收命令行参数{for (int i = 0; i < argc; i++) {printf("argv[%d]: %s\n", i, argv[i]); // 遍历字符指针数组argv}return 0;}

运行结果:字符数组中只有一个元素,就是我们输入的命令

[yzy@VM-4-4-centos day8]$ ./procargv[0]: ./proc

如果再多输入几个参数,就能观察到如下运行结果:

[yzy@VM-4-4-centos day8]$ ./proc agr1 arg2 arg3argv[0]: ./procargv[1]: agr1argv[2]: arg2argv[3]: arg3

总结

实际上我们输入的命令行参数,就是一个个的 C 字符串:

② 命令行参数的意义

思考

为什么要存在命令行参数呢?—— 帮助我们能够,给同一个程序,设计出不同的业务功能。(⭐)

👉 举个小例子,比如我想要实现这样一个计算器:

如果输入./cal,则会提示该程序的正确用法:Usage: ./cal -[a|s] x y;输入./cal -a 1 2,cal 程序可以输出 1 + 2 的结果;输入./cal -s 4 2,cal 程序可以输出 4 - 2 的结果。

#include<stdio.h>#include<stdlib.h> // atoi -- 函数原型:int atoi(const char *nptr); // 将C字符串转换成整数#include<string.h> // strcmp// cal命令的用法手册void Usage(const char* cal) {printf("Usage: %s -[a|s] x y\n", cal);}int main(int argc, char* argv[]) // 接收命令行参数{// 输入的参数个数不为4if (argc != 4) {Usage(argv[0]);return 1; // 退出程序}// 保存第3个和第4个参数 int x = atoi(argv[2]);int y = atoi(argv[3]);// 根据不同参数,执行不同功能,然后输出结果if (strcmp(argv[1], "-a") == 0) {printf("%d + %d = %d\n", x, y, x + y); }else if (strcmp(argv[1], "-s") == 0) {printf("%d - %d = %d\n", x, y, x - y); }else {Usage(argv[0]);return 1; // 退出程序}return 0;}

运行结果:

[yzy@VM-4-4-centos day8]$ ./cal # 命令使用手册Usage: ./cal -[a|s] x y[yzy@VM-4-4-centos day8]$ ./cal -a 1 2 # 实现加法1 + 2 = 3[yzy@VM-4-4-centos day8]$ ./cal -s 4 2 # 实现减法4 - 2 = 2

③ 总结

命令行参数可以让同一个命令,通过带上不同的选项,表现出不同的功能和作用。比如:ls -lls -l -als -l -a -i。这就是命令行参数的意义。

我们平常在 VS 中写代码,都知道程序是从 main 函数开始执行,那是谁调用的 main 函数呢?

编程者写的 main 函数被void mainCRTStartup(void)函数调用的,这个函数定义在 VS 安装目录的某个 .c 文件中(VS 的版本不同,存放的位置也不同),它会执行一些初始化操作,如从内核中获取命令行参数和环境变量值、初始化全局变量、初始化 IO 等等所需各项准备之后,为调用main(argc, argv, env)函数做好了准备。(⭐)

我们可以通过 main 函数的参数,可以传递命令行参数和环境变量。(⭐)

1.9 环境变量的组织方式

① 前言

main 函数除了可以传递两个和命令行参数相关的参数 argc 和 argv 以外,还可以传递第三个参数 env:

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

这也是 main 函数获取环境变量的方式。(⭐)

通过给 main 函数第三个参数传参,把一个个环境变量传递给当前程序,当前程序运行起来变成进程,就意味着当前这个进程获取到了这些环境变量。

每个被 bash 创建的子进程都会接收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的字符串(环境变量)。

② 通过 main 的第三个参数获取环境变量

/* proc.c */#include<stdio.h>#include<string.h>int main(int argc, char* argv[], char* env[]) // 通过第三个参数接收环境变量{for (int i = 0; env[i]; i++) {// 循环结束条件为env[i],遍历到NULL停止printf("env[%d]: %s\n", i, env[i]); // 遍历字符指针数组env}return 0;}

运行结果:获取到了当前 bash 内的所有环境变量。(因为环境变量被 bash 创建的子进程proc继承下去了)

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

③ 通过全局变量 environ 获取环境变量(了解)

C/C++ 提供了一个全局二级指针变量char** environ,指向存放环境变量地址的字符指针数组char* env[]

#include <stdio.h>int main(){extern char **environ;for (int i = 0; environ[i]; i++) {printf("%s\n", environ[i]); // 等价于 *(environ + i)}return 0;}// 注意:libc中定义的全局变量 environ 指向环境变量表,environ 没有包含在任何头文件中,所以在使用时要用extern声明

拓展:下面程序运行会报错吗?—— 不会。

#include<stdio.h>void show() {printf("hello show\n");}int main(){show(10, 20);return 0;}

分析:10 和 20 这两个参数是传给了 show 函数,它们被压入了 show 函数栈帧中,实际上在 show 函数中是可以通过某些指针操作来获取到 10 和 20 的,只是比较复杂。上述程序中的二级指针 environ 一样的可以通过某种方式在 main 的压栈结构中指向传入的命令行参数char* env[](环境变量表),来获取到环境变量。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。