Linux学习之路 -- 进程篇 -- 环境变量

本文将介绍环境变量的相关内容,以及相关操作

目录

一、main

二、环境变量

1.为什么要有环境变量?

2.环境变量的特性以及命令行操作

<1>命令行操作:

<2>特性:


一、main

介绍一下main函数的参数。

在一些教材上,我们经常可以看到main函数是可以带参数的。

int main(int argc, char* argv[])
{//......return 0;
}

这里我们并不知道main的参数里面存的是啥,不过可以确定的是char* argv是一个存放字符指针的数组,我们可以把它里面的每一个元素打印出来,看看里面到底有什么东西。

#include<stdio.h>
int main(int argc, char* argv[])
{for(int i = 0; i < argc; i++){printf("argv[%d]:%s\n",i,argv[i]);}return 0;
}

运行结果

root@iZuf6at4ih6u7gbg2vxumnZ:~/linux/Linux-ubantu/pro-nice# 这一长串的字符是bash给我们输出的命令行字符串,我们输入的其实是一段长字符串,在这里被bash分割成了一个一个的小字符串。这里其实就是以空格为分割符,将长字符串分割成了一个一个的小字符串,并且我们将小字符串的首元素的地址放在argv这个字符数组里面。将分割的字符串个数放进argc这个变量里面。然后将对应得参数传个main即可。

所以上述的代码也可以这样写

int main(int argc, char* argv[])
{for(int i = 0; argv[i]; i++){printf("argv[%d]:%s\n",i,argv[i]);}return 0;
}

那我们为什么要这样做呢?

下面用一段代码来说明其中的缘由

#include<stdio.h>
int main(int argc, char* argv[])
{if(argc != 2){printf("操作错误,请输入标准命令:./Main.c -number[number属于1-3]\n");}else{if(strcmp(argv[1],"-1") == 0){printf("funtion 1\n");}else if(strcmp(argv[1],"-2") == 0){printf("funtion 2\n");}else if(strcmp(argv[1],"-3") == 0){printf("funtion 3\n");}else{printf("unkown\n");}}return 0;}

运行结果

这里需要输入一段命令,这段命令必需带一个选项,通过argv参数,我们就可以获取用户所需的选项,从而实现不同的功能,其实就和ls 命令带不同选项会有不同效果是一样的,系统这样做的原因也是因为这个。argc,argv就是命令行参数,这也是Linux指令选项的基础。

二、环境变量

环境变量其实和上述命令行参数有相似之处。在了解它之前我们需要知道的是,环境变量不是只有一个,而是由一堆,而且他们彼此之间没有什么关系。它们一般是系统内置的具有特殊用途的变量,这里的变量其实跟我们常用的编程语言上的变量没啥区别,本质上都是开辟空间。在系统的环境变量,本质是系统自己开辟空间,给他名字和内容即可,当然,bash也是可以开辟空间的。

1.为什么要有环境变量?

在回答这个问题之前,我们先看一个现象,在每一次运行一个可执行程序时,我们总要在这个程序名前面加上绝对或者相对路径,而在执行系统命令(本质上也是可执行程序)时,就不需要加上路径?

要运行一个程序的前提是我们必需找到这个程序,那为什么系统指令不要提供路径,系统就能找到它们呢?其实这就是因为环境变量PATH, 我们可以用echo $PATH查看这个环境变量。这个变量其实是一个长字符串(冒号为分割符),里面记录了一些路径,当我们调用系统指令时,系统就会沿着PATH所提供的路径依次搜索这个命令对应的可执行程序。而我们自己写的程序并没有添加到这个路径里面,所以系统不知道从哪里开始寻找,所以在运行时,前面就要加上特定的路径。

如果我们想要让我们自己写的可执行程序不用加路径,做法有两种,一是把我们写的可执行程序直接加到上述路径下的目录中,不过不建议这样做。另一种是把我们当前程序的路径添加到PATH变量中即可。使用“ PATH = 当前程序的绝对路径 :$PATH(这个一定要加,要不然原来的路径就全被覆盖掉了) ”  命令,就可以把当前可执行程序的路径添加进PATH变量中。如果我们直接让PATH = 当前程序的绝对路径,这样会导致其他的系统指令全部失效。如果发生这种情况,直接重新登录即可,这是因为我们修改的PATH是在内存里面的,不是磁盘上的。当我们重新登录系统时,系统会重新从磁盘的配置文件/脚本里加载PATH变量。在./bash_profile里面可以配置一些环境变量,系统会从这个文件里读取环境变量的导入脚本,不建议随便配置。

前面说过,环境变量不止一个,而是有很多个,它们记录了用户的一些相关信息,比如登录者是谁,当前在哪条路径下等等。我们可以用env命令查看当前所有的环境变量

这些信息就是为什么操作系统始终知道登录的用户是谁,在哪里等等。如果想要查找特定的环境变量,使用"echo $变量名"即可

下面是我搜集的一些环境变量所代表的含义,如有缺漏,可自行补充。

  1. HOME - 用户的主目录路径。
  2. PATH - 执行命令时要搜索的目录列表,目录之间用冒号(:)分隔。
  3. PWD - 当前工作目录的路径。
  4. USER - 当前登录的用户名。
  5. SHELL - 当前用户的登录shell的路径。
  6. HOSTNAME - 当前系统的主机名。
  7. TERM - 当前终端的类型。
  8. EDITOR - 用户默认的文本编辑器的路径。
  9. PAGER - 用户默认的分页器的路径。
  10. MAIL - 用户邮箱文件的路径,通常是/var/spool/mail/username
  11. LANG - 定义了系统默认的语言和字符集,如en_US.UTF-8
  12. LC_ALL - 覆盖所有地区的设置,如果设置了LC_ALL,它会优先于LANG
  13. DISPLAY - X Window系统使用的显示服务器和屏幕的名称,格式通常是hostname:display_number.screen_number
  14. SSH_AUTH_SOCK - SSH认证代理的UNIX域套接字的路径。
  15. HTTP_PROXY/HTTPS_PROXY - HTTP/HTTPS代理服务器的地址。
  16. NO_PROXY - 不使用代理服务器的地址列表。
  17. LD_LIBRARY_PATH - 动态链接器搜索共享库的路径。
  18. MANPATH - 搜索手册页的路径。
  19. PS1 - 主提示符,是你在终端看到的命令提示符

2.环境变量的特性以及命令行操作

<1>命令行操作:

echo:打印特定的环境变量

export:增加环境变量 export  变量名 = 变量内容

env:查看所有的环境变量

getenv接口:这个函数可以获得特定的环境变量,const char* p  =  getenv("环境变量名");如果获取成功,环境变量字符串的地址,如果失败,就返回NULL。单个环境变量可以用于身份识别。

environ 指针:这是一个二级指针,指向的也是env环境变量表,下面用一段代码来演示一下(使用时要用extern声明)

unset: 清除环境/本地变量。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main(int argc, char* argv[],char* env[])
{extern char** environ;for(int i = 0; environ[i]; i++){printf("environ[%d] -> %s\n",i,environ[i]);}return 0;
}

运行结果:

<2>特性:

其实我们的main函数,还有一个参数 char* env[] ,这个就是环境变量,我们可以用一段代码来验证一下。

int main(int argc, char* argv[],char* env[])
{for(int i = 0; env[i]; i++){printf(" env[%d] ---> %s\n",i,env[i]);}return 0;
}

运行结果:

我们发现,这里的env就是环境变量,env本身和argv这个数组几乎是一样的,只不过存的东西不同,形式是一样,都以NULL结尾,每个元素存一个环境变量字符串。而这里环境变量被作为参数传递给了main函数,那么是谁传递给main的呢?答案是该进程的父进程,也就是bash。bash进程本身是由一张环境变量表的,创建子进程后,它会把自己的环境变量表env,传个子进程,也就是说环境变量是可以被子进程继承下去的。这里我们可以用一段代码来验证一下。

int main(int argc, char* argv[],char* env[])
{printf("I am a process , pid: %d, ppid:%d\n",getpid(),getppid());for(int i = 0; env[i]; i++){printf("---------------env[%d] : %s\n",i,env[i]);}pid_t id = fork();if(id == 0){printf("——-------------------------\n");printf("I am a child , pid: %d, ppid:%d\n",getpid(),getppid());for(int i = 0; env[i]; i++){printf("---------------env[%d] : %s\n",i,env[i]);}}sleep(1);
}

运行结果

这里我们可以看到,子进程也能打印出环境变量,所以我们也可以得出环境变量有全局性。

三、本地变量

除了环境变量,还存在本地变量,我们只需要将 “ 变量名 = 变量内容” 输入命令行即可,再用echo $变量名 ,就能查看本地变量。env是无法看到本地变量的。当然,你也可以使用set命令,这个命令会打印出所有的变量,包括本地变量和环境变量。需要注意的是,本地变量只在bash内部有效,也就是说,本地变量是不能被子进程所继承下去的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/636826.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

17. map和set的基本使用

1. 关联式容器 在初阶阶段&#xff0c;我们已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque等&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身。 那什么是关联式容器&#xff…

数据输入输出流(I/O)

文章目录 前言一、数据输入输出流是什么&#xff1f;二、使用方法 1.DataInputStream类2.DataOutoutStream类3.实操展示总结 前言 数据输入输出流也是将文件输入输出流打包后使用的对象。相比于文件输入输出流&#xff0c;数据输入输出流提供了简单易用的方法去操作不同类型的数…

Text2sql的一些技巧

最近看到了一篇关于text2sql的文章&#xff0c;以及一些论文。对使用模型做text2sql给了一些不错的建议。 参考文章&#xff1a;24年大模型潜力方向&#xff1a;大浪淘沙后的Text-to-SQL和Agent - 知乎 论文&#xff1a;https://arxiv.org/pdf/2403.09732.pdf 关于模型的建议 …

红外接收器的原理以及在STM32和51单片机中的应用

基本介绍&#xff1a; 红外接收器是一种用于接收红外线信号的装置&#xff0c;常见于各种电子设备中&#xff0c;如电视遥控器、空调遥控器等。它能够接收来自发射器发送的红外信号&#xff0c;并将其转换成电信号&#xff0c;以便设备进行相应的操作。红外接收器通常包含红外光…

AI大模型日报#0420:开源模型击败GPT-4、西湖大学蛋白质通用大模型、GPT的七条经验

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。 标题: 开源模型打败GPT-4&#xff01;LLM竞技场最新战报&#xff0c;Cohere Command R上线 摘要: GPT-4在LLM竞技场被开源模型Cohere的…

9.Godot数组|遍历|静态变量|对象|调试

数组和字典的遍历 数组的概念 数组是一组数据的集合。在程序中负责批量处理数据。数组中的元素可以包括各个类型的数据&#xff0c;也可以对数组内数据类型进行限定。可以通过 数组名【数字】 的形式来访问数组元素&#xff0c;数字 0 代表数组的第一个元素。数组可以通过调用…

GPT状态和原理 - 解密OpenAI模型训练

目录 1 如何训练 GPT 助手 1.1 第一阶段 Pretraining 预训练 1.2 第二阶段&#xff1a;Supervised Finetuning有监督微调 1.3 第三阶段 Reward Modeling 奖励建模 1.4 第四阶段 Reinforcement Learning 强化学习 1.5 总结 2 第二部分&#xff1a;如何有效的应用在您的应…

Linux——匿名管道

为什么要有进程间通信&#xff1f; 在操作系统中&#xff0c;进程是独立运行的程序&#xff0c;多个进程之间要想互相协作完成任务&#xff0c;就需要进程间通信。 什么是进程间通信&#xff1f; 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程资源共享&#…

C语言数据结构之链表

目录 前言 \color{maroon}{前言} 前言1.链表的概念及结构2.链表的分类3.无头单向非循环链表的实现4.带头双向循环链表的实现5.顺序表和链表的对比 前言 \color{maroon}{前言} 前言 在上一篇博客中我们提到&#xff0c;线性表包括顺序表和链表&#xff0c;顺序表在上篇博客中已…

普通人切入抖音的黄金赛道 软件自动生成文字动画视频 3天15个作品涨粉5000

文字动画&#xff0c;就是导入一段文字&#xff0c;用软件可以自动生成一条文字动画视频&#xff0c;因为这是软件自动生成的&#xff0c;所以过原创的话是很简单没什么问题的。 这种视频的特点是什么? 首先第一点就是非常简单&#xff0c;找好素材直接导入软件就可以自动生成…

java-Spring-入门学习-第二天(单例模式和多例模式)

目录 Bean作用域 单例模式(默认可以不写) Spring下的 AutoWired 依赖注入 JaveEE下的 Resource 依赖注入 多例模式 Bean作用域 ​在Spring框架中&#xff0c;Bean是按照作用域来创建的&#xff0c;常见的作用域有两种&#xff1a;Singleton 和 Prototype。Singleton (单例…

STM32 HAL库F103系列之ADC实验(一)

ADC工作原理&#xff1a; 1、输入通道&#xff1a; 2、转换序列&#xff1a; A/D转换被组织为两组&#xff1a;规则组&#xff08;常规转换组&#xff09;和注入组&#xff08;注入转换组&#xff09; 规则组最多可以有16个转换&#xff0c;注入组最多有4个转换 规则组和注入…