Linux相关概念和易错知识点(12)(命令行参数、环境变量、本地变量)

news2024/11/25 2:42:01

1.命令行参数

(1)main函数的参数int  argc和char*  argv[]是什么?

main函数可以带参数,即int  main(int  argc,  char*  argv[]),(int  argc,  char*  argv[])叫做命令行参数列表,int argc叫参数的个数,char* argv[]叫参数的列表。

当我们在Linux中输入./test执行程序时:argc == 1,argv[0] == "./test",当程序加载时我们写的一行字符串都会被根据空格拆分成多个小字符串,作为参数传进argv

下面就是个很好的例子

我特地在打印时使用了选项1、选项2来标识每个被拆分的字符串来作为引导。事实上,指令的本质就是C语言,这其实就是ls -a -l这种指令选项实现的原理。如test -opt1 -opt2 -opt3就会被转为4个字符串,分别对应argv的4个元素argv[0] ~ argv[3]。在main函数内显式调用argv[1]、argv[2]...,通过字符串比较对这些argv[num]字符串进行匹配,进而根据判断语句实现不同功能匹配。

在Linux指令中,命令行参数使得程序能有不同的功能和表现。但在我们自己平时写的代码中,很少用到这种功能,所以一般main函数不写参数。

(2)命令行参数是如何传递的?

ls -a -l...这一行被视为一个字符串,这个字符串首先被用户的父进程Shell(Linux中是-bash,CLI的具体实现程序)拿到,父进程将这个字符串按照空格分解为多个字符串,进而构建出了argc和argv(argv是动态分配空间的,根据拆分字符串数量决定开辟空间,argv末尾有结束标志,如argv[8] == NULL)。也就是说实际上最先拿到argc和argv这两个数据的是父进程-bash

当父进程创建子进程,也就是调用开始程序的时候,子进程会独立一份代码和数据,保持独立性,其中这部分数据里就有命令行参数列表argc和argv。也就是说bash启动程序形成的argc和argv列表其子进程也能看到。

这里需要注意的是,main并不是程序入口,main函数也是被其它函数调用的,在main函数前还有CRTstartup(),这个函数就会针对父进程传下来的数据调用main函数并决定是否传参数。main函数结束后的返回值也是交给CRTstartup()的。

2.环境变量

(1)main函数的第3个参数char*  env[]是什么?

main函数的参数其实还有一个char* env[](环境变量表的指针,实际上是char**  env)

这是另外一张表,每个元素都是一个环境变量,env[0]、env[1]......即可全部调用。最后一个元素之后同样有NULL标志。所有环境变量的格式都是key=value,如USER=SGlow,这看上去似乎是在展示某种属性,事实上环境变量是我们很多进程能运行起来的重要基础。很多指令和程序的执行都依赖环境变量里面的信息

使用env指令可以查看当前环境变量

(2)环境变量的全局属性

环境变量具有“全局”属性。具体地说,环境变量表继承自父进程,也可以继承给子进程。当我们用户登录Shell时,-bash进程被创建,此时它就拥有了一份环境变量表。不论这个用户以任何形式创建进程,归根到底这些进程都是bash的子进程,于是所有的进程用的环境变量表都是一样的。

我们可以在命令行使用env来对比test.c打印出来的环境变量表,发现是一样的。

因此我们称其为全局属性。至于环境变量出现的目的以及更多细节,我们后续会提到。

(3)借助PATH属性进一步了解环境变量

我们要思考一个问题:./test可以运行程序,但为什么test就不行呢?我们现在已经知道ls、pwd的本质也是C语言写的可执行程序,那为什么那些指令执行直接输入可执行程序名就可以了呢?

事实上,我们输入的每一条指令都会到/usr/bin等规定目录下去找,如果这些目录找不到就必须使用./test来指定调用程序了。像ls、pwd这些C语言程序就是如此,因为系统能找到这些程序,所以不用./ls或者./pwd

下面是/usr/bin目录下的一些指令对应的可执行程序

我们如果将我们写的可执行程序放到这个目录里,那就自然可以按指令的形式顺利运行了。

但这不是唯一的方案,系统也不会只到这一个目录下查找。PATH环境变量就指定了系统以何种顺序进行查找

使用echo $PATH就可以查找当前环境变量的PATH。$是一个标志,后面跟的就是要查找的属性名

我们可以使用PATH=$PATH:$PWD来加上我们要执行的程序的目录。PWD也是环境变量的一种,它指向了我们当前的工作目录,指令pwd就是读取该环境变量。

需要注意的是PATH=(路径)会直接将右侧字符串替换回去,所以我们要保证格式规范,还有不要直接PATH=$PWD,这样默认路径就被覆盖了。这会导致一些指令无法运行(注意不是全部)

由于命令行是在-bash这个进程下进行的,所以每当我们cd时,环境变量的PWD就会修改,当有程序运行起来时,就会读取当前的PWD作为自己的cwd进程属性,这就是为什么bash的子进程都知道自己的cwd的原因。如果这些子进程再创建子进程,它们也会继承父进程的环境变量,知道自己的cwd。当然之前也说过,在代码中我们可以使用chdir("(路径)")来显式改变cwd,但我们要知道默认路径的根本是读取bash进程下的PWD。理解程序运行起来时进程属性cwd是如何确定的对我们深入理解环境变量有很大帮助。

(4)环境变量的配置

PATH=$PWD会覆盖默认路径,怎么抢救呢?事实上,我们只需要重新登陆系统即可解决。因为环境变量是内存级别的,我们指令修改PATH是修改的bash进程对应内存空间中的环境变量数据,而磁盘上的数据不会受到影响,所以退出重进就能完全恢复。

登录时,系统首先要创建bash进程来启动CLI,保证命令行的正常执行,所有用户登陆后都要干这件事。创建bash进程分为创建PCB和从磁盘中读取环境变量配置文件信息到内存两步,读取配置文件的本质是为了在内存中配置自己的配置文件,因为不同的用户初始时有不同的环境变量,像PWD、HOME、USER这些都需要按用户设置。

配置完环境变量后bash进程就基本创建完成了,各个环境变量都有值了,像HOME和PWD最开始都是指向自己的家目录(是因为HOME存的是这个值,所以那里才叫家目录)。同时bash也是一个进程,这个进程也有自己的cwd,它会使用类似chdir()的操作设置自己的cwd,这个cwd就是刚刚读取到的配置文件中HOME的路径,即家目录。

我们发现环境变量对于每个用户是独一无二的,是用户登录后需要尽快导入的数据,在bash进程的创建中也有很重要的作用。当我们理解清环境变量的内存级属性,以及它和bash之间的关系之后,我们对环境变量又有了一个新的认识,也对之前的进程的属性的认识更上一层楼。

但还有一些问题,这个配置文件在哪里?我们可以自己改吗?

这个配置文件在我们家目录下,当登录时会读取.bash_profile和.bashrc到内存中以修改形成当前用户的环境变量信息。因为.bash_profile和.bashrc在这个目录下,所以读取文件时的HOME就被默认设置为了该路径,因此配置的环境变量HOME就是该路径,导致家目录是该路径。家目录被设置在该目录的根本就是因为.bash_profile和.bashrc在这个目录下

在.bash_profile里面我们可以看到PATH的默认信息,这是存储在磁盘上的,每次登录都会被读取到内存上。我们可以加上自己的想要查询的路径,保存退出后,用source .bash_profile使配置文件生效,之后登录就能自动加到PATH环境变量

我们重新登录就会发现我们添加的默认信息已经生效了,当环境变量被配置时,我们的自定义路径就会在PATH中,我们之后就无需手动PATH=$PATH:(路径)

(5)一些环境变量的功能

在进程属性中我们能查到是谁启动的进程(uid),从而和文件的拥有组、所属组、other的uid匹配,进而控制权限。但是系统怎么知道谁启动的进程呢?就是USER=(用户名),当登录后导入环境变量,创建bash时系统就知道我们是谁了,不管创建多少进程,由进程数据的继承规则,系统永远知道我们用户的身份。

SHELL告诉我们登录时启动的Shell进程对应程序的路径,因为一个系统中可能有不同的Shell版本;LOGNAME和NAME一般来讲是一致的,是指当前的登录用户;OLDPWD是指上一条cd路径,它显然直接帮助cd - 这个指令实现

(6)环境变量的读取

env是整体查看,获取具体的信息可以使用管道 + grep筛选

getenv((环境变量key)),返回其value

unistd.h中有一个全局的变量char** environ(指向char* env[]数组),extern声明之后就可以使用

3.本地变量

(1)如何创建和使用

我们直接在命令行使用a=5,b=10就是在定义本地变量。我们可以借助while和for循环来进行一些批量化操作

其中说明(( 表达式 ))是算术表达式,其返回值用于条件判断,$(( 表达式 ))返回用于变量赋值。在(( 表达式 ))的表达式不需要写$(变量),能自动识别本地变量,运算结果也能自动修改变量。[[ 表达式 ]]和[ 表达式 ]还支持一些文本的比较,但都要写$。一般来说,我们略微了解即可。这种用法还催生出了Shell脚本.sh用来处理批量化任务(类似于Makefile),.sh本质也是一个文件,./之后也是按照Shell的逻辑一行一行执行。

(2)本地变量和本地变量表

用户登陆,创建bash进程时,除了环境变量表的导入,bash还创建了一个本地变量表,当我们在命令行使用a=10这种操作时a被直接加到本地变量表。

export a可以将本地变量mv到环境变量表中。export操作相当于直接将指针移动到环境变量表,移动到env中后本地变量表就没有这个变量了。

通过export,我们也可以使用export b=100直接添加到环境变量表中。unset (key)取消环境变量

(3)通过本地变量进一步了解环境变量

环境变量是可以被继承下去的,是一个全局有效的配置信息,每个子进程都能得到这个信息;而本地变量不能,它也不能被子进程看到。

在和本地变量的对比中,我们可以进一步看到环境变量的全局属性。系统的配置信息,尤其是指导性配置信息(当前用户是谁USER,工作路径PWD)都是交给环境变量来保管的,而不是本地变量。环境变量的导入是系统配置起效的一种表现,因为所有程序运行起来都是进程,而所有进程都遵循系统的配置信息,这就说明这个配置信息有了用处,否则配置信息就只能存在文件里,它并没有对系统造成实质性的规范和影响。

和本地变量相比,环境变量更倾向于在进程间传递只读数据,虽然我们可以进行内存级修改,但毕竟环境变量是程序启动的根基,所以一般都是以读的形式访问,这和本地变量有很大区别。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【YOLO学习】YOLOv3详解

文章目录 1. 网络结构1.1 结构介绍1.2 改进 2. 训练与测试过程3. 总结 1. 网络结构 1.1 结构介绍 1. 与 YOLOv2 不同的是,YOLOv3 在 Darknet-19 里加入了 ResNet 残差连接,改进之后的模型叫 Darknet-53。在 ImageNet上 实验发现 Darknet-53 相对于 ResN…

VSCODE驯服日记(三):配置C++环境

1. 下载mingw64,解压后把bin并添加到环境变量 1>编译器介绍 mingw:专为windowsgcc:多平台msvc :windows,且配合vs使用更佳 注意与调试器gdb和lldb的区别 2. 安装vscode插件: 安装C/C插件 安装code ru…

力扣之1322.广告效果

题目: sql建表语句: Create table If Not Exists Ads (ad_id int,user_id int,action ENUM (Clicked, Viewed, Ignored) ); Truncate table Ads; insert into Ads (ad_id, user_id, action) values (1, 1, Clicked); insert into Ads (ad_id, use…

Sublime Text 下载地址分享

Sublime Text官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘123云盘为您提供Sublime Text最新版正式版官方版绿色版下载,Sublime Text安卓版手机版apk免费下载安装到手机,支持电脑端一键快捷安装https://www.123684.com/s/kPxoTd-dCnxHSublime Text官方版下载丨最新版下…

双十一可以买什么物品?重磅推荐五款好用品牌!

距离今年的双十一盛典仅剩数十日,您是否已将心爱商品添加至购物车中了呢?还在犹豫未满载的朋友也无需焦虑,特意为您精选了五款好用的宝贝推荐,旨在为您的购物清单增添几分灵感与便捷,期待能为您的双十一购物之旅增添一…

GPU 是否有朝一日可以取代 CPU?

讨论 GPU 是否能够取代 CPU,需要从两者的基本架构、设计目的、性能表现、应用领域等多个方面进行分析。虽然你提到的4060显卡的核心频率接近服务器 CPU 的频率,这看起来似乎有一些相似性,但 GPU 和 CPU 的设计思路和适用场景差异显著&#xf…

18448 最小生成树

### 思路 使用Kruskal算法求解图的最小生成树。Kruskal算法通过对所有边按权值排序,然后逐步选择最小权值的边,确保不会形成环,直到构建出最小生成树。 ### 伪代码 1. 读取输入的结点数n和边数m。 2. 读取每条边的信息,存储在边列…

羊城杯2024WP

羊城杯-2024 web web2 进题信息搜集一下,dirsearch发现了login路由可访问,先随便点一下,发现了一个文件读取: http://139.155.126.78:30148/lyrics?lyricsRain.txt 我尝试了一下: http://139.155.126.78:30148/lyrics…

【教学类-77-02】20241007青花瓷纹理纸(手工)

背景需求: 大班《我是中国人》主题下,有一个“青花瓷”的主题,各种平面绘画 这些青花瓷花瓶、盘子都是平面的,我想能不能做个立体的,所以前期设计了“青花瓷立体卡”【教学类-77-01】20241005青花瓷立体书-CSDN博客文…

构建 10 万卡 GPU 集群的技术挑战

构建 10 万卡 GPU 集群的技术挑战 摘要 揭示AI训练集群关键基础设施挑战,探讨突破现有AI瓶颈的必要性与10万GPU集群(如OpenAI、Meta)建设所面临挑战与需求。 构建网络拓扑,需权衡多层交换机成本、带宽与维护。本文对比Ethernet与…

JDBC 快速入门

JDBC 快速入门 搭建步骤代码实现数据库java 代码 搭建步骤 准备数据库官网下载数据库连接驱动jar 包。https://downloads.mysql.com/archives/c-j/创建 java 项目,在项目下创建 lib 文件夹,将下载的驱动 jar 包复制到文件夹里选中 lib 文件夹右键 ->…

通信工程学习:什么是ICP网络内容服务商

ICP:网络内容服务商 ICP,全称Internet Content Provider,即网络内容服务商,是指那些通过互联网向用户提供各种类型内容服务的组织或个人。ICP在数字化时代扮演着至关重要的角色,它们不仅是信息的传播者,更是…

微服务获取用户信息和OpenFeign传递用户

问题一: 网关已经完成登录校验并获取登录用户身份信息。但是当网关将请求转发到微服务时,微服务又该如何获取用户身份呢? 由于网关发送请求到微服务依然采用的是Http请求,因此我们可以将用户信息以请求头的方式传递到下游微服务…

机器人技术基础(1-3章坐标变换)

位置矢量的意思是B坐标系的原点O相对于A坐标系的平移变换后的矩阵: 齐次坐标最后一个数表示缩放倍数: 左边的是T形变换矩阵,右边的是需要被变换的矩阵:T形变换矩阵的左上角表示旋转,右上角表示平移,左下角最…

使用 NVIDIA H100 上的 Azure 机密计算释放隐私保护 AI 的潜力

通过 NVIDIA H100 上的 Azure 机密计算释放隐私保护 AI 的潜力 文章目录 前言一、机密计算二、使用 NVIDIA H100 Tensor Core GPU 的 Azure 机密计算1. 安全功能2. 可扩展性和可编程性三、场景1. 模型机密性2. 推理/提示机密性3. 使用私有数据进行微调4. 多方培训结论前言 这是…

71.【C语言】动态内存管理(重点)(4)

本文为数据结构打下基础 备注:数据结构需要掌握指针,结构体和动态内存管理 目录 6.常见的动态内存的错误 1.对空指针解引用 2.对动态空间的越界访问 3.对非动态内存空间进行free释放 4.使用free只释放开辟的内存空间的一部分 5.对同一块动态内存多次释放 6.动态开辟的…

多线程编程-定时器

定时器相当于一个“闹钟”,在日常生活中,我们需要闹钟的辅佐,在代码中,也经常需要“闹钟”机制(网络通信中经常需设定一个超时时间)。 一.定时器的使用 在Java标准库中,也停供了定时器的实现。…

华为OD机试 - 约瑟夫问题(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试真题(Python/JS/C/C)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,…

日语发音

这里写目录标题 一个视频教你搞懂日语音调!【日语入门课】小白入门轻松学!最全的日语零基础教程合集!唱儿歌学日语~(已完结) 一个视频教你搞懂日语音调! 中文 阴平(第一声&#xff…

【d61】【Java】【力扣】【递归】3304. 找出第 K 个字符 I

思路 递归考虑:就像正常一样想出来思路,然后递归调用的地方,当作一个已经确定的量(可直接说一个值,这样就不会一直向下层想) 注意绝对不要在递归调用的地方一直往下层想,绝对不要,…