当前位置: 首页 > news >正文

【Linux】命令行参数 | 环境变量(四)

目录

前言:

一、命令行参数:

1.main函数参数

2.为什么有它?

二、环境变量:

1.main函数第三个参数

2.查看shell本身环境变量

3.PATH环境变量

4.修改PATH环境变量配置文件 

5.HOME环境变量

6.SHELL环境变量

7.PWD环境变量

8.USER和LOGNAME环境变量

9.OLDPWD环境变量

三、理解环境变量:

1.本地变量(临时变量)

2.set查看所有变量

3.export导入环境变量

4.unset取消环境变量

5.环境变量的全局属性 

6.环境变量表

四、命令总结:

总结:


前言:

我们已经了解了进程的很多概念,上次讲到了进程调度算法,这次我们来一个更炸裂的环境变量,大家应该都学过JAVA,每次都要下载并配置环境变量,这次,我们来彻底搞懂它。

一、命令行参数:

1.main函数参数

我们平时写C语言,main函数有参数吗?其实main函数有参数,但是我们从来不会写,这次我们把环境变量参数都打印出来并看看都是什么:

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

等等,这里你可能无法直接编译生成可执行程序:

 

我们平时使用的VS后面其实默认添加了,所以我们再makefile中指定标准:

此时再次make就不会报错。

我们在命令行中多传入几个参数并观察结果: 

当然也可以是其他字符:

所以,我们把main函数参数中的argv叫做命令行参数列表;argc叫做参数的个数。

2.为什么有它?

比如现在写一个只要两个参数的程序:

#include<stdio.h>
#include<string.h>// code -opt1/-opt2/-opt3
int main(int argc, char *argv[])
{if (argc != 2) {printf("Usage: code -opt\n");return 1;}if (strcmp(argv[1], "-opt1") == 0){printf("功能1\n");}else if (strcmp(argv[1], "-opt2") == 0){printf("功能2\n");}else if (strcmp(argv[1], "-opt3") == 0){printf("功能3\n");}else {printf("默认功能\n");}return 0;
}

我们来测试一下:

有没有似曾相识?我们平时使用的命令都会加上选项,而这些命令都是C语言实现的。可以让同一个程序,根据命令行参数的选项,表现出不同的功能。比如:指令中选项的实现。

在命令行中,我们平时输入的命令其实是一串字符串,首先会被shell(bash命令行)拿到,之后按照空格打散,形成一张表(argv)和元素个数(argc)

命令行启动的程序,父进程都是shell。对于数据(尤其是只读的),子进程也能看到。 

main函数也是被调用的,父进程都是shell,一般传入下面三个参数:

二、环境变量:

1.main函数第三个参数

我们刚才看到main函数的参数有三个,main函数第三个参数env,我们这次打印出所有的环境变量:

以key-value方式构建的,具有“全局”属性的变量,叫做全局属性。

常见的环境变量:

PATH: 指定命令的搜索路径

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

SHELL: 当前Shell,它的值通常是/bin/bash

2.查看shell本身环境变量

在命令行想看shell本身自己的环境变量,输入env即可:

和之前打印出来的一样。

这次我们修改代码:

3.PATH环境变量

为什么系统知道命令在usr/bin目录下?我们可以让他认识我们的路径吗?

PATH环境变量,告诉了shell,执行命令时,应该去哪个路径下查。如果我们想指定看一个环境变量,可以使用如下命令:

这代表当shell运行任何一个命令时,首先要查PATH中的路径,之后看里面有没有对应的命令。

PATH是一个路径集合,是系统可执行文件的搜索路径的集合

所以,我们可以修改PATH,把自己的路径添加到PATH中,就可以直接执行自己的命令了。

至于为什么有的命令还能跑,我们以后再解释。但是现在有一个问题,我们把之前的路径都覆盖了,怎么恢复?其实在环境变量加载的时候,我们就已经把其加载到了bash进程内部,是内存级的,保存在进程的上下文中。也就是相当于我们malloc出来一块空间,此时把malloc空间中的内容修改了,所以我们重启一下Xshell即可。

所以在修改PATH时,不要直接把PATH修改为我们想修改的路径,要把之前的路径加上去,再添加我们的路径:

所以环境变量PATH本质就是内存级的变量通过shell维护,可以通过一定方式修改PATH变量。所以这次我们关掉Xshell依旧还是原来的PATH路径,不会添加你之前添加的内容。

4.修改PATH环境变量配置文件 

但是,这些内容一开始是从哪里的来的?最开始PATH环境变量一定不再内存中,而是在系统的配置文件中。

当我登陆的时候,会启动一个shell进程,此时就会读取用户和系统相关的环境变量的配置文件形成自己的环境变量表。

所以我们修改配置文件,我们一旦登录Linux一定是一个具体的用户在登陆,登录后一定处在自己的家目录下,所以系统中家目录下会存在两个配置文件(.bash_profile, .bashrc)。当bash启动时,就会读取这两个环境变量,形成自己的环境变量信息。

所以我们将之前code所在文件路径添加到.bash_profile文件中,并观察效果:

如果没有成功(因为刚才已经添加过了临时新的环境变量,所以这里没有执行该命令),让一个更改后的配置文件生效可以使用该命令:

source .bash_profile

我们之前讲解过uid,也就是进程内部会记录是谁启动的这个进程。但是你启动进程的时候,系统怎么会知道你是谁?并且把你的uid写入到pcb中呢?因为:

5.HOME环境变量

因为命令行执行的命令都是bash的子进程,所以当我们切换路径的时候,也就把bash的cwd的属性给改了。 所以创建的所有进程路径都源自于bash的cwd路径:

当我们切换路径,就会改变bash的cwd:

所以为什么最开始我们处于家目录中?因为最开始读取配置文件中的环境变量(HOME),然后bash把自己的cwd设置在了HOME变量中。 

所以系统读取配置文件时,首先一定知道登录的用户是谁,一旦发现不是root,之后就会更改为/home/XXX把环境变量设置好,之后chdir更改cwd即可。把bash的cwd改为当前工作路径(家目录下)。

6.SHELL环境变量

还有一个环境变量是SHELL,它会记录系统启动时,使用的哪个shell(当前就是bash):

7.PWD环境变量

还有一个环境变量是PWD,是保存当前路径的:

为什么要这么做?

我们可以通过代码获取环境变量,如果按照之前的方法,是获取所有环境变量之后匹配,这样并不优雅,系统提供了对应的函数getenv:

getenv函数获取环境变量的内容,返回char*。获取成功返回值,失败返回NULL。

  • PWD是一个具体的命令,用于显示当前目录路径。

  • CWD 是一个概念,表示程序或进程当前的工作目录。

 PWD的输出取决于进程的 CWD,而 CWD 是进程可以动态修改的。

8.USER和LOGNAME环境变量

我们直接打印出环境变量观察这两者的内容:

当前两者是一致的。此时执行su -:

我们再先以gan身份登录,之后登录到跟用户:

所以当我们登陆的时候,LOGNAME和USER是一致的;su -执行后本质是以root身份登录的;而su root不会改变原来的LOGNAME和USER,只是改变了执行身份。

所以我们区分使用系统的用户以环境变量USER区分。

我们可以修改envtest.c代码来观察现象:

之后先以gan用户执行,之后su -再次执行该代码:

也就是说我们可以通过代码来进行身份认证,我们这里可以演示一下:
 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>int main()
{//可以让我的程序识别用户身份,只让gan用户访问const char* who = getenv("USER");if (strcmp(who, "gan") == 0) {printf("执行程序正常命令\n");return 0;} else{printf("无权访问!\n");return 1;}return 0;
}

这样就可以写一些可以对用户权限进行控制的程序。 

9.OLDPWD环境变量

我们先记录当前路径:

之后cd ~回家,查看env。发现有一个OLDPWD环境变量记录我们上次所在路径:

再次cd -:

所以PWD记录当前工作路径,OLDPWD记录你上次所在工作路径。所以cd -就是基于这个环境变量实现的。 

以上为认识环境变量。

三、理解环境变量:

系统提供的具有"全局"属性的变量。

1.本地变量(临时变量)

shell也支持我们直接在本地定义变量:

这样定义的变量不属于环境变量,我们使用env并查不到。

在命令行输入的"a=10"这样的语句其实是一段字符串,被shell先读到,shell(一个进程)也就会把这个字符串维护起来,就相当于malloc一块空间。这种变量叫做本地变量不会被环境变量查到。

2.set查看所有变量

如果现在想查到环境变量和本地变量都查到,可以使用set来查询:

本地变量一般给自己用。 

3.export导入环境变量

我们也可以把本地变量导出到环境变量:

以下这个图方便各位更好地理解环境变量,本地变量和argv表: 

当我们export i之后,会导入环境变量。

bash重启以后,export的变量也会消失

当然也可以直接使用export b=100直接导入环境变量。

所以bash不仅认识变量,还认识while循环等语句,所以衍生出了一门shell脚本语言。

设计一个只执行一次的程序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>int main()
{char* isrunning = getenv("ISRUNNING");if (isrunning == NULL){while(1){printf("当前进程首次启动!\n");sleep(1);}} else {printf("当前进程已经运行了!\n");}return 0;
}

环境变量是可以被子进程继承的。

4.unset取消环境变量

我们使用unset取消导入的环境变量(unset不仅可以取消你自己定义的环境变量,还可以取消大多数非只读的环境变量和 shell 变量,包括一些由系统或 shell 自动设置的环境变量。不过,只读变量(如PWD等)无法被取消): 

5.环境变量的全局属性 

环境变量可以被所有bash之后的进程全部看到,所以环境变量具有"全局属性"。系统的配置信息,尤其是具有"指导性"的配置信息,它是系统配置起效的一种表现。

进程具有独立性,环境变量可以用来进程间传递数据(只读数据)。

6.环境变量表

其实还有第三种获取环境变量的方法:

使用environ获取环境变量, environ是一个包含在unistd.h中的全局变量,是一个二级指针,它指向环境变量的表:

我们可以用代码来使用一下它:

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

四、命令总结:

env :  查看shell本身自己的环境变量。

set : 查看所有变量,包括临时变量。

unset : 取消非只读环境变量。

export : 导入环境变量

总结:

我们目前已经认识了很多的环境变量,但是其实使用的还是很少,而且它到底有什么用?我们会在下一节进程地址空间来更加具体的理解。加油吧,各位!

相关文章:

【Linux】命令行参数 | 环境变量(四)

目录 前言&#xff1a; 一、命令行参数&#xff1a; 1.main函数参数 2.为什么有它&#xff1f; 二、环境变量&#xff1a; 1.main函数第三个参数 2.查看shell本身环境变量 3.PATH环境变量 4.修改PATH环境变量配置文件 5.HOME环境变量 6.SHELL环境变量 7.PWD环境变…...

算法002——复写零

力扣——复写零点击即可跳转 这道题还是运用 双指针&#xff0c;我们从左往右开始&#xff0c;让 cur 0&#xff0c;dest 0,当我们循环时&#xff0c;会覆盖后面的值&#xff0c;所以从左到右无法实现&#xff0c;我们运用 从右到左的方式。 以示例一数组为例&#xff0c;从…...

例子 DQN + CartPole: 深入思考一下,强化学习确实是一场智能冒险之旅!

强化学习的概念 在技术人员眼里&#xff0c;深度学习、强化学习&#xff0c;或者是大模型&#xff0c;都只是一些算法。无论是简单&#xff0c;还是复杂&#xff0c;我们都是平静的看待。当商业元素日益渗透进技术领域&#xff0c;人人言必称大模型的时候。技术人该反思一下&a…...

java 实现xxl-job定时任务自动注册到调度中心

xxl-job 自动注册(执行器和任务) 前言 xxl-job是一个功能强大、简单易用、高可用且可扩展性强的分布式定时任务框架/分布式任务调度平台。它适用于各种需要定时任务调度的场景,并可根据业务需求进行灵活配置和扩展。 xxl-job简介 xxl-job是一个开源的分布式定时任务框架,…...

esp32串口通信

1、线路图 2、打开电脑的串口终端 3、eps32通过串口往电脑的串口终端输出信息&#xff1a; from machine import UART, Pin import time# 初始化UART0&#xff0c;波特率设置为115200 uart UART(0, baudrate115200, tx1, rx3)# 主循环 while True:# 要发送的消息#某些串口终…...

蓝桥杯备赛-前缀和-可获得的最小取值

问题描述 妮妮学姐手头有一个长度为 nn 的数组 aa&#xff0c;她想进行 kk 次操作来取出数组中的元素。每次操作必须选择以下两种操作之一&#xff1a; 取出数组中的最大元素。取出数组中的最小元素和次小元素。 妮妮学姐希望在进行完 kk 次操作后&#xff0c;取出的数的和最…...

UniApp 中封装 HTTP 请求与 Token 管理(附Demo)

目录 1. 基本知识2. Demo3. 拓展 1. 基本知识 从实战代码中学习&#xff0c;上述实战代码来源&#xff1a;芋道源码/yudao-mall-uniapp 该代码中&#xff0c;通过自定义 request 函数对 HTTP 请求进行了统一管理&#xff0c;并且结合了 Token 认证机制 请求封装原理&#xff…...

边缘计算+多模态感知:户外监控核心技术解析与工程部署实践!户外摄像头监控哪种好?户外摄像头监控十大品牌!格行视精灵VS海康威视VS大华横评!

一、核心参数解析与选型逻辑 1.环境适应性设计 极端天气防护&#xff1a;优先选择IP66/67防护等级的设备&#xff0c;例如格行视精灵通过IP67防水防尘设计可应对暴雨、沙尘暴等复杂环境&#xff0c;其密封轴承结构可有效防止水汽侵蚀内部电路。 温度耐受范围&#xff1a;北方…...

Spring项目-抽奖系统(实操项目)(ONE)

^__^ (oo)\______ (__)\ )\/\ ||----w | || || 一&#xff1a;前言&#xff1a; 随着互联网技术的快速发展&#xff0c;线上营销活动已成为企业吸引用户、…...

STM32-智能小车项目

项目框图 ST-link接线 实物图&#xff1a; 正面&#xff1a; 反面&#xff1a; 相关内容 使用L9110S电机模块 电机驱动模块L9110S详解 | 良许嵌入式 测速模块 语音模块SU-03T 网站&#xff1a;智能公元/AI产品零代码平台 一、让小车动起来 新建文件夹智能小车项目 在里面…...

Python:字符串常见操作

find(子字符串&#xff0c;开始位置下标&#xff0c;结束位置下标) 注意&#xff1a;开始位置和结束位置下标可以省略&#xff0c;表示在整个字符串中查找 stasdfghjkl print(st.find(a))#输出结果为0&#xff0c;表明a在第一个位置默认从零开始&#xff0c;找不到则返回-1 …...

Redis 哈希(Hash)

Redis 哈希(Hash) 概述 Redis 哈希&#xff08;Hash&#xff09;是一种特殊的键值对类型&#xff0c;它允许存储结构化的数据&#xff0c;例如一个对象或记录。每个哈希值可以包含多个字段&#xff0c;每个字段又可以存储一个字符串值。这使得Redis哈希非常适合用于存储对象的…...

Windows对比MacOS

Windows对比MacOS 文章目录 Windows对比MacOS1-环境变量1-Windows添加环境变量示例步骤 1&#xff1a;打开环境变量设置窗口步骤 2&#xff1a;添加系统环境变量 2-Mac 系统添加环境变量示例步骤 1&#xff1a;打开终端步骤 2&#xff1a;编辑环境变量配置文件步骤 3&#xff1…...

react 路由跳转的几种方式

在 React 中&#xff0c;路由跳转通常通过 react-router-dom&#xff08;或类似的路由库&#xff09;来实现。以下是几种常见的路由跳转方式&#xff1a; 1. 使用 <Link> 组件 <Link> 是最简单的路由跳转方式&#xff0c;它会生成一个 <a> 标签&#xff0c…...

2.你有什么绝活儿?—Java能做什么?

1、Java的绝活儿&#xff1a;要问Java有什么绝活&#xff0c;我觉得它应该算是一位魔法师&#xff0c;会的绝活儿有很多&#xff0c;要说最能拿得出手的当属以下三个。 1.1 平台无关性&#xff1a;Java可以在任何地方施展魔法&#xff0c;无论是Windows、Linux还是Mac&#xf…...

2025年2月文章一览

2025年2月编程人总共更新了17篇文章&#xff1a; 1.2025年1月文章一览 2.《Operating System Concepts》阅读笔记&#xff1a;p2-p8 3.《Operating System Concepts》阅读笔记&#xff1a;p9-p12 4.《Operating System Concepts》阅读笔记&#xff1a;p13-p16 5.《Operati…...

C++ | 面向对象 | 类

&#x1f47b;类 &#x1f47e;语法格式 class className{Access specifiers: // 访问权限DataType variable; // 变量returnType functions() { } // 方法 };&#x1f47e;访问权限 class className {public:// 公有成员protected:// 受保护成员private:// 私有成员 }…...

leetcode:2164. 对奇偶下标分别排序(python3解法)

难度&#xff1a;简单 给你一个下标从 0 开始的整数数组 nums 。根据下述规则重排 nums 中的值&#xff1a; 按 非递增 顺序排列 nums 奇数下标 上的所有值。 举个例子&#xff0c;如果排序前 nums [4,1,2,3] &#xff0c;对奇数下标的值排序后变为 [4,3,2,1] 。奇数下标 1 和…...

Visionpro cogToolBlockEditV2.Refresh()

在 C# 中使用 cogToolBlockEditV2.Refresh() 方法主要用于刷新 CogToolBlockEditV2 控件的显示状态&#xff0c;适用于动态更新界面或重新加载工具块&#xff08;ToolBlock&#xff09;的场景。以下是具体说明和典型应用场景。 基本作用 刷新控件显示&#xff1a;当修改了与 C…...

Apache Spark中的依赖关系与任务调度机制解析

Apache Spark中的依赖关系与任务调度机制解析 在Spark的分布式计算框架中,RDD(弹性分布式数据集)的依赖关系是理解任务调度、性能优化及容错机制的关键。宽依赖(Wide Dependency)与窄依赖(Narrow Dependency)作为两种核心依赖类型,直接影响Stage划分、Shuffle操作及容…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...

Linux中INADDR_ANY详解

在Linux网络编程中&#xff0c;INADDR_ANY 是一个特殊的IPv4地址常量&#xff08;定义在 <netinet/in.h> 头文件中&#xff09;&#xff0c;用于表示绑定到所有可用网络接口的地址。它是服务器程序中的常见用法&#xff0c;允许套接字监听所有本地IP地址上的连接请求。 关…...