免费企业网站,预付网站建设服务费如何入账,惠州广告公司有哪些,网站301跳转怎么做的一、环境变量的基本概念
其实#xff0c;我们早就听说过环境变量#xff0c;比如在学习 JAVA / Python 的时候#xff0c;会在 Windows 上配置环境变量#xff1a; 环境变量到底是什么呢#xff1f; 环境变量#xff08;environment variables#xff09;一般是指在操作…一、环境变量的基本概念
其实我们早就听说过环境变量比如在学习 JAVA / Python 的时候会在 Windows 上配置环境变量 环境变量到底是什么呢 环境变量environment variables一般是指在操作系统中用来指定操作系统运行环境的一些参数。这些参数通常有特殊的用途。如我们在编写 C/C 代码的时候在链接的时候我们从来不知道我们所链接的动态静态库在哪里但是照样可以链接成功生成可执行程序原因就是有相关环境变量帮助编译器进行查找。环境变量通常具有某些特殊用途环境变量在系统当中通常具有全局特性。 1、常见环境变量 PATH当前用户指定命令的搜索路径。HOME指定用户的主工作目录即用户登陆到 Linux 系统中时默认的目录。SHELL当前 Shell它的值通常是 /bin/bash。HISTSIZE命令历史记录保存数量。Centos 6.7 默认是 3000 条 命令 history 可以查看所有命令历史记录。搭配管道 history | wc -l 可以查看命令历史记录的行数。 2、查看环境变量方法 命令echo $PATH PATH 是环境变量的名称查看指定环境变量。 命令env 查看系统中所有的环境变量。 3、环境变量PATH 我们编写的 C/C 代码编译生成的可执行程序是不是一个命令呢 是的。 在 Linux 中任何一个可执行程序具有可执行权限x就称之为它是一条命令。 其实我们听过的程序、命令、指令、可执行程序等等都是一个概念。 既然是同一个概念那为什么运行 ls 等命令不用带 ./ 当前路径而运行我们自己的可执行程序 proc 必须要带 ./proc 当前路径呢 环境变量 PATH 中保存的是指定命令的搜索路径。 因为 ls 等命令是在系统的特定路径下保存起来的而 proc 命令没有保存在 PATH 指定的这些路径中系统执行命令又只会在 PATH 指定的这些路径中搜索那么系统就找不到我们的 proc 命令所以就报错了。 那有没有什么办法可以让可执行程序 proc 不用带 ./ 当前路径就可以直接运行呢 方法 1把 proc 拷贝到环境变量 PATH 指定的任一路径下。 方法 2把 proc 所在路径添加到环境变量 PATH 中。注意自己添加的环境变量系统重启后是不会被保存的 $ PATH$PATH:/home/ll/xxx/10# :冒号是分隔符
# 注意PATH/home/ll/xxx/10不能这样写必须加上$符号否则会把PATH中所有内容覆盖掉 运行效果图 注意如果我们不幸把环境变量给覆盖掉了不用担心。环境变量既然是变量说明它是可以被赋值的即在用户登录时通过用户目录下的配置文件赋值的所以只需要重新登录就好了。 比如在家目录下的 .bash_profile 文件这些文件 不建议自己去随意修改 4、环境变量HOME
分别在 root 和普通用户下执行 cd ~ 和 pwd 查看家目录分别是 /root 和 /home/xyl为什么得到的结果不一样呢 因为不同用户的家目录中的配置文件不一样所以不同用户下的环境变量 HOME 也是不一样的。 [rootVM-0-12-centos ~]$ echo $HOME
/root
[xylVM-0-12-centos ~]$ echo $HOME # 指定用户的主工作目录
/home/xyl 二、与环境变量相关的命令 echo显示某个环境变量值。export设置一个新的环境变量。env显示所有环境变量。unset清除环境变量。set显示本地定义的 shell 变量和环境变量。 1、通过 C 库函数获取环境变量getenv 1getenv 和 setenv 函数介绍 name环境变量的名称。返回值环境变量的内容。 #include stdlib.hchar *getenv(const char *name); // 获取环境变量
int setenv(const char *name, const char *value, int overwrite); // 更改或添加环境变量 2getenv 使用举例 // 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 创建子进程然后由子进程执行用户输入的命令。 三、环境变量和本地变量 在命令行中我们通常可以定义两种变量 环境变量环境变量通常具有全局属性可以被子进程继承下去 环境变量实际上是在当前 bash 的上下文中定义的。所以在当前命令行解释器 bash 内可以被访问到在 bash 创建的子进程内也可以被访问到。 #include stdio.h
#include stdlib.hint main()
{char* env getenv(MYENV);if(env){printf(%s\n, env);}return 0;
} 直接运行发现没有结果说明该环境变量根本不存在。 导出环境变量export MYENVhello world 再次运行程序发现有结果了。说明环境变量是可以被子进程继承下去的。 本地变量只能在当前 shell 命令行解释器内被访问不可以被子进程继承 [xylVM-0-12-centos 10]$ MY_VALhello world # 定义本地变量在bash内定义的 如何查看本地变量呢 和查看环境变量方式一样 [llVM-0-12-centos 10]$ echo $MY_VAL # 在当前命令行解释器bash内访问本地变量
hello world 如何证明本地变量不能被子进程继承 // proc.c
#include stdio.h
#include stdlib.h // getenvint main()
{printf(%s\n, getenv(MY_VAL));return 0;
} 运行结果段错误。 分析 当我们输入 ./proc 后bash 会创建子进程来执行 proc 程序。但因为本地变量 MY_VAL 只能在当前 bash 内被访问不能被其子进程继承所以子进程中的 getenv(MY_VAL) 函数获取不到本地变量 MY_VAL导致程序报错。 该怎么解决这个问题呢 可以将本地变量 MY_VAL 设置成环境变量。 [llVM-0-12-centos 10]$ exprot MY_VAL # 把本地变量MY_VAL导出成环境变量 导入成功 再次运行程序成功访问到了环境变量 MY_VAL。 上面说到我们在命令行上运行的大部分命令都是 bash 创建子进程来执行的而本地变量不能被子进程继承那为什么使用 echo 命令却可以访问本地变量呢 四、命令行参数 1、main 函数的参数列表 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;
} 运行结果字符数组中只有一个元素就是我们输入的命令。 [llVM-0-12-centos 10]$ ./proc
argv[0]: ./proc 如果再多输入几个参数就能观察到如下运行结果 [llVM-0-12-centos 10]$ ./proc agr1 arg2 arg3
argv[0]: ./proc
argv[1]: agr1
argv[2]: arg2
argv[3]: arg3 总结 实际上我们输入的命令行参数就是一个个的 C 字符串 ./proc、arg1、arg2、arg3传给了 main 函数 2、命令行参数的意义 为什么要存在命令行参数呢? 帮助我们能够给同一个程序设计出不同的业务功能。 举个小例子比如我想要实现这样一个计算器 如果输入 ./cal则会提示该程序的正确用法Usage./cal -[a|s] x y; 输入 ./cal -a 1 2cal 程序可以输出 1 2 的结果 输入 ./cal -s 4 2cal 程序可以输出 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;
} 运行结果 [llVM-0-12-centos 10]$ ./cal # 命令使用手册
Usage: ./cal -[a|s] x y
[llVM-0-12-centos 10]$ ./cal -a 1 2 # 实现加法
1 2 3
[llVM-0-12-centos 10]$ ./cal -s 4 2 # 实现减法
4 - 2 2 3、总结 命令行参数可以让同一个命令通过带上不同的选项表现出不同的功能和作用。 比如ls -l、ls -l -a、ls -l -a -i。这就是命令行参数的意义。 我们平常在 VS 中写代码都知道程序是从 main 函数开始执行那是谁调用的 main 函数呢 编程者写的 main 函数被 void mainCRTStartup(void) 函数调用的这个函数定义在 VS 安装目录的某个 .c 文件中VS 的版本不同存放的位置也不同它会执行一些初始化操作如从内核中获取命令行参数和环境变量值、初始化全局变量、初始化 IO 等等所需各项准备之后为调用 main(argc, argv, env) 函数做好了准备。可以通过 main 函数的参数可以传递命令行参数和环境变量。 五、环境变量的组织方式 main 函数除了可以传递两个和命令行参数相关的参数 argc 和 argv 以外还可以传递第 3 个参数 env
int main(int argc, char* argv[], char* env[]);
这也是 main 函数获取环境变量的方式。
通过给 main 函数第三个参数传参把一个个环境变量传递给当前程序当前程序运行起来变成进程就意味着当前这个进程获取到了这些环境变量。 每个被 bash 创建的子进程都会接收到一张环境表环境表是一个字符指针数组每个指针指向一个以 ’\0’ 结尾的环境字符串环境变量。 1、通过 main 的第三个参数获取环境变量
// proc.c
#include stdio.h
#include string.hint 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 后面的内容并返回。 2、通过全局变量 environ 获取环境变量了解
C/C 提供了一个全局二级指针变量 char** environ指向存放环境变量地址的字符指针数组 char* env[ ]。
#include stdio.hint 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.hvoid show()
{printf(hello show\n);
}int main()
{show(10, 20);return 0;
} 分析10 和 20 这两个参数是传给了 show 函数它们被压入了 show 函数栈帧中实际上在 show 函数中是可以通过某些指针操作来获取到 10 和 20 的只是比较复杂。 上述程序中的二级指针 environ 可以通过某种方式在 main 的压栈结构中指向传入的命令行参数 char* env[ ]环境变量表来获取到环境变量。