Linux操作系统之进程(四):命令行参数与环境变量

article/2025/7/22 12:18:43

目录

前言:

什么是命令行参数

什么是环境变量

认识环境变量

PATH环境变量

HOME

USER

OLDPWD

本地变量

本地变量与环境变量的差异

核心要点回顾

结语: 


前言:

大家好,今天给大家带来的是一个非常简单,但也十分重要知识点,命令行参数与环境变量的有关内容。要理解本文的知识点,需要有一些前置的基础,具体可以查看我的Linux系统文章的专栏:跳转地址

什么是命令行参数

从广义的概念上来讲,命令行参数是指在执行程序时通过命令行界面(如终端、命令提示符等)传递给程序的额外信息或选项。

大家在Linux系统中在终端输入各种指令,后面的选项其实就是命令行参数。

那么大家知道这些命令,例如ls -l,ps -ajx的本质是什么吗?

今天让我来告诉你吧。他们的本质其实就是一个程序。

大家在学习C语言时,main函数后面有着参数吗?大多数情况下都没有吧。

但实际上,在 C 语言 中,main() 函数可以接收 命令行参数(command-line arguments),其标准形式如下:

int main(int argc, char *argv[]) { ... }

 我们把main函数的(int argc,char * argv[])称为命令行列表,argc为参数的个数,argv是参数的清单。

参数类型说明
argcint参数个数(Argument Count),包括程序名本身
argvchar*[]参数向量(Argument Vector),字符串数组,存储所有参数

这些都是理论,大家可能理解不了,那么就实战来看一下吧!

 我们现在有以下文件:

Makefile:

# 定义编译器和编译选项
CXX = g++
CXXFLAGS = -Wall -std=c++11# 定义目标文件和可执行文件名
TARGET = test
SRC = test.c# 默认目标
all: $(TARGET)# 直接生成可执行文件(不生成.o文件)
$(TARGET): $(SRC)$(CXX) $(CXXFLAGS) -o $@ $<# 清理生成的文件
clean:rm -f $(TARGET)# 运行程序
run: $(TARGET)./$(TARGET).PHONY: all clean run

test.c:

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

我们在终端,当前文件夹路径下输入make生成可执行文件test,随后./test运行该文件:

我们看见,输出的结果为1,参数打印的结果刚好是我们的运行命令:./test

那我们再多测试几次呢? 

我们大概可以得出结论,我们运行程序,就相当于调用main函数,给main函数传参。

按照空格打散的规则,划分为不同的字符串。argc就代表这些参数的个数,而argv这个字符串数组则负责保存这些参数。

我们在main函数中通过argv可以获取到这些参数,从而实现指令的那些不同选项的功能的划分,例如,我们可以写一个简单的例子:
我们修改test代码如下:

#include <stdio.h>int main(int argc, char *argv[]) 
{if(strcmp(argv[1],"-l") == 0){printf("执行-l命令\n");}else if(strcmp(argv[1],"-a") == 0){printf("执行-a命令\n");}else{printf("没有找到命令\n");}
}

 make重新编译生成可执行文件。

这样,就模拟实现了一个简单的指令根据不同选项执行对应选项的功能。


什么是环境变量

刚刚我们只展示了main函数的两个参数,但实际上,在 C 语言 中,除了标准的 argc 和 argv 之外,main() 函数在某些环境下(如 Linux/UNIX 系统)还可以接收 第三个参数 envp,用于访问 环境变量

那么什么是环境变量呢?

请看以下实验:
修改test.c代码如下:
 

#include <stdio.h>
#include<string.h>int main(int argc, char *argv[], char *envp[]) 
{for(int i = 0; envp[i] != NULL; i++){printf("第%d个环境变量: %s\n", i, envp[i]);}
}

运行test,有以下结果:

 会给我们打印出这一系列的,形如:Key=Value格式的信息。

以此格式构建的,具有“全局”属性的变量,叫做全局变量。环境变量 是操作系统级别的 Key=Value 配置,用于影响所有子进程。


认识环境变量

接下来,就让我们来认识几个环境变量,来增加我们对环境变量这个概念的理解与认识。

PATH环境变量

 PATH 是操作系统中最重要的环境变量之一,它决定了 系统在哪些目录中查找可执行程序。当你输入一个命令(如 ls 、ps )时,系统会按照 PATH 中列出的目录顺序搜索该命令对应的可执行文件。

我们知道,其实每个指令都是系统已经写好的可执行文件,那么为什么我们在执行我们的可执行文件时,都是路径+文件名的形式,比如可执行文件在当前路径,我们就是./+路径名,如果在其他路径,就是其他路径+文件名,可是我们执行系统指令时,却从来没有加过路径,输入名字就可以直接执行,这是为什么呢?

答案是,如果不带路径,我们的系统就找不到我们的文件。要是想让系统找到,由于系统默认在user/bin等目录下找,我们可以把exe拷贝到该目录。

但是为什么系统知道命令都在user/bin等目录下,这是什么原因呢??

答案就是环境变量PATH,PATH告诉shell应该去哪里查!

PATH环境变量由多个路径组成,每一个路径之间:作为分隔符。Shell默认会去以冒号为分隔符的多个子路径下去查命令。

既然这样,如果我们修改一下PATH,增加我们当前test所在工作路径,那么岂不是执行test时就不用输入前置路径了吗?

请看以下实验:

我们用echo打印出该PATH环境变量,可以看见一开始是没有当前目录的。

随后我们pwd找到当前目录,通过PATH=$PATH:[当前目录]

修改PATH,可以看见,现在已经修改完毕了。

那我们此时使用test来运行可以吗?

依然是不行的,这是因为test本身其实是一个Shell的内置命令,优先级高于我们自己的程序,所以我们需要修改一下我们的可执行文件的名字。找到Makefile,修改最后生成文件名为Test。

重新编译生成可执行文件,输入Test:

 可以发现已经可以直接运行了,那我们在进入上级目录试试:

也是可以的,这就验证了我们之前所说的:Shell默认会去以冒号为分隔符的多个子路径下去查命令。 

但实际上,通过PATH=这个操作来修改是临时的,当我们重启终端,再次查看就会恢复为一开始的PATH。那么有没有什么方法可以永久修改呢?

有的兄弟,有的,像这样的方法我们还有九个(bushi)

在每次重新打开终端时,我们得先想一下,最初的PATH等环境变量,他们是怎么来的呢?

答案是在系统的配置文件里

用户登录云服务器时,系统会启动一个 登录 Shell 进程。该 Shell 会依次读取系统级和用户级的配置文件,最终形成自己的环境变量表。当 Shell 通过 fork() 创建子进程时,子进程会继承这份环境变量表的副本;若子进程调用exec() 加载新程序,默认会继续传递该环境变量表。(exec()代表 “执行”(execute),用于在当前进程中加载并运行一个新的程序。它不是一个单独的命令,而是一系列系统调用和 Shell 内置命令的统称。)

我们在自己的家目录输入 ll 指令,可以在这些文件中找到两个文件:

这两个文件就是我们的配置文件 (在部分系统中,.profile可能叫做.bash_profile)。

我们可以打开这两个文件看一眼:

可以看见,密密麻麻的全是配置文件。这也就是每次登录后,用户都第一时间处于自己的家目录的原因,因为只有在自己的家目录,才能找到这两个配置文件。

我们在.profile文件中可以查看到,这里是对我们的PATH环境变量配置的地方,我们可以尝试更改.profile文件:

在末尾添加这一段代码:

# 添加自定义路径到 PATH
if [ -d "/home/ubuntu/dailycode/命令行参数与环境变量博客代码" ] ; thenPATH="/home/ubuntu/dailycode/命令行参数与环境变量博客代码:$PATH"
fi

注意,我们这里双引号的内容,应该替换成你想要增加的路径。我这里想要增加的是:“/home/ubuntu/dailycode/命令行参数与环境变量博客代码”该路径。

保存并退出,我们打印一下PATH观看,

发现并没有失效,所以我们可以使用一下source命令使一个配置文件生效:

 可以看见,PATH环境变量成功被改变了,重新进入终端,也是相同的PATH:

(记得把.profile改回原样哦~) 


HOME

在环境变量表中,还有一个环境变量叫做HOME,这个环境变量又有什么作用呢?

首先我们要先明确一个过程:

"当用户通过SSH登录Linux系统时,系统会为该会话创建一个新的bash进程作为登录Shell。这个bash进程首先会读取/etc/profile和用户主目录下的.profile等配置文件,通过这些配置文件设置自己的环境变量表和工作目录(cwd),然后才向用户呈现交互界面。此时的环境变量配置是专属于这个bash进程的,其他进程(包括后续创建的子进程)会继承这份环境变量的副本,但无法反向修改父进程的环境。"

"bash进程在初始化时,会将自己的当前工作目录(cwd)设置为用户主目录(即$HOME环境变量指向的路径)。所以这也就是为什么,我们在登录后默认处于自己的家目录的原因。HOME变量其实就是指向该用户的家目录"


USER

在环境变量里,有一个叫做USER的环境变量。

这个环境变量用来标识当前登录用户的用户名,通常可以用来实现 程序判断用户身份,从而根据用户不同实现不同的供暖。

我们可以举一个小例子:

修改test.c代码如下:
 

#include <stdio.h>
#include<string.h>
#include<stdlib.h>int main(int argc, char *argv[], char *envp[]) 
{const char *who=getenv("USER");if(strcmp(who,"root")==0){printf("你是root用户,执行root命令\n");}else if(strcmp(who,"ubuntu")==0){printf("你是ubuntu用户,执行ubuntu命令\n");}else{printf("你是其他用户,执行其他命令\n");}
}

运行后有以下结果 

随后我们用su命令将自己切换为root,再次运行,就会得到不一样的结果, 


OLDPWD

 

OLDPWD如同他的名字一样,就是随时指向上一次访问的位置 ,它保存了用户在执行 cd 命令切换目录 之前 的路径。

这也是我们cd -命令的实现逻辑。


本地变量

在Shell中,我们也可以定义本地变量。

我们可以发现,定义的本地变量并不在env表里,此时我们可以使用set,unset来将本地变量设置到,或者用export将本地变量提升到环境变量表里。

但请注意,这个设置到本地变量里仍然只在当前Shell里生效。使用export将本地变量提升到环境变量表里后,我们创建子进程,子进程也会看见我们提升的本地变量。


本地变量与环境变量的差异

  1. 环境变量可以被子进程继承,而本地变量不可以
  2. 环境变量可以被bash之后的所有进程看见,所以环境变量具有全局性

为什么呢?:

a、系统的配置信息,尤其是具有指导性的配置信息,他是系统配置起效的一种表现

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


核心要点回顾

  1. 命令行参数

    • 通过main函数的argc和argv参数接收

    • 允许程序根据不同的输入参数执行不同的功能

    • 是Linux命令选项功能实现的基础机制

  2. 环境变量

    • 通过main函数的envp参数或getenv()函数访问

    • 是系统级别的全局配置信息

    • 影响所有子进程的行为

    • 包括PATH、HOME、USER等重要变量

  3. 关键区别

    • 命令行参数是程序运行时临时传入的

    • 环境变量是系统预先配置的全局设置

    • 环境变量可以被子进程继承,具有持久性


结语: 

通过本文的学习,我们深入探讨了命令行参数和环境变量这两个在Linux系统中至关重要的概念。他们两个概念是程序与操作系统交互的重要桥梁,也是开发者必须掌握的基础知识。

希望本文能帮助你更好地理解Linux系统的工作机制。如果有任何疑问,欢迎在评论区留言讨论!

 


http://www.hkcw.cn/article/hwBYHoNSke.shtml

相关文章

IDA dumpdex经典脚本(记录)

一个dumpdex的IDA插件 毕业了,暂时用不着了,存起来 import idaapi import structdef dumpdex(start, len, target):rawdex idaapi.dbg_read_memory(start, len)fd open(target, wb)fd.write(rawdex)fd.close()def getdexlen(start):pos start 0x20mem idaapi.dbg_read_mem…

第2期:APM32微控制器键盘PCB设计实战教程

第2期&#xff1a;APM32微控制器键盘PCB设计实战教程 一、APM32小系统介绍 使用apm32键盘小系统开源工程操作 APM32是一款与STM32兼容的微控制器&#xff0c;可以直接替代STM32进行使用。本教程基于之前开源的APM32小系统&#xff0c;链接将放在录播评论区中供大家参考。 1…

Redis的安装与使用

网址&#xff1a;Spring Data Redis 安装包&#xff1a;Releases tporadowski/redis GitHub 解压后 在安装目录中打开cmd 打开服务&#xff08;注意&#xff1a;每次客户端连接都有先打开服务&#xff01;&#xff01;&#xff01;&#xff09; 按ctrlC退出服务 客户端连接…

Redis 难懂命令-- ZINTERSTORE

**背景&#xff1a;**学习的过程中 常用的redis命令都能快速通过官方文档理解 但是还是有一些比较难懂的命令 **目的&#xff1a;**写博客记录一下&#xff08;当然也可以使用AI搜索&#xff09; 在Redis中&#xff0c;ZINTERSTORE 是一个用于计算多个有序集合&#xff08;So…

7.atlas安装

1.服务器规划 软件版本参考&#xff1a; https://cloud.google.com/dataproc/docs/concepts/versioning/dataproc-release-2.2?hlzh-cn 由于hive3.1.3不完全支持jdk8,所以将hive的版本调整成4.0.1。这个版本没有验证过&#xff0c;需要读者自己抉择。 所有的软件都安装再/op…

RabbitMQ和MQTT区别与应用

RabbitMQ与MQTT深度解析&#xff1a;协议、代理、差异与应用场景 I. 引言 消息队列与物联网通信的重要性 在现代分布式系统和物联网&#xff08;IoT&#xff09;生态中&#xff0c;高效、可靠的通信机制是构建稳健、可扩展应用的核心。消息队列&#xff08;Message Queues&am…

【技能篇】RabbitMQ消息中间件面试专题

1. RabbitMQ 中的 broker 是指什么&#xff1f;cluster 又是指什么&#xff1f; 2. 什么是元数据&#xff1f;元数据分为哪些类型&#xff1f;包括哪些内容&#xff1f;与 cluster 相关的元数据有哪些&#xff1f;元数据是如何保存的&#xff1f;元数据在 cluster 中是如何分布…

[3D GISMesh]三角网格模型中的孔洞修补算法

&#x1f4d0; 三维网格模型空洞修复技术详解 三维网格模型在扫描、重建或传输过程中常因遮挡、噪声或数据丢失产生空洞&#xff08;即边界非闭合区域&#xff09;&#xff0c;影响模型的完整性与可用性。空洞修复&#xff08;Hole Filling&#xff09;是计算机图形学和几何处…

基于Spring Boot+Vue 网上书城管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

[ctfshow web入门] web81

信息收集 新增过滤:&#xff0c;伪协议都有:&#xff0c;这意味着伪协议不能用了 if(isset($_GET[file])){$file $_GET[file];$file str_replace("php", "???", $file);$file str_replace("data", "???", $file);$file st…

2025年应用心理学与社会环境国际会议(ICAPSE 2025)

2025年应用心理学与社会环境国际会议&#xff08;ICAPSE 2025&#xff09; 2025 International Conference on Applied Psychology and Social Environment 一、大会信息 会议简称&#xff1a;ICAPSE 2025 大会地点&#xff1a;中国北京 审稿通知&#xff1a;投稿后2-3日内通…

Windows 11 家庭版 安装Docker教程

Windows 家庭版需要通过脚本手动安装 Hyper-V 一、前置检查 1、查看系统 快捷键【winR】&#xff0c;输入“control” 【控制面板】—>【系统和安全】—>【系统】 2、确认虚拟化 【任务管理器】—【性能】 二、安装Hyper-V 1、创建并运行安装脚本 在桌面新建一个 .…

Redis 数据恢复的月光宝盒,闪回到任意指定时间

在数据库的运维工作中&#xff0c;DBA 应该选择哪一种方案&#xff0c;确保 Redis 数据库崩溃后可以对数据进行回档&#xff0c;恢复业务运行&#xff1f; 一般情况下&#xff0c;DBA 可以通过 Redis 原生的持久化机制&#xff0c;如 RDB 快照持久化或者 AOF 日志持久化的方案…

鸿蒙 HarmonyOS - SideBarContainer 组件自学指南

在日常开发中&#xff0c;如果你有类似「左侧导航 右侧内容」的布局需求&#xff0c;比如后台管理界面、文件管理器、设置页等&#xff0c;​​SideBarContainer​​ 是非常值得掌握的组件。它自带侧边栏和主内容区的分离机制&#xff0c;还支持折叠、拖拽、控制按钮和多种显示…

一个Mybatisplus组件扫描不当引起的bug:弄巧成拙,认真的锅,自我怀疑

在我们系统基建层的业务组件包 sby-biz-component 中&#xff0c;最初&#xff0c;我写了两个业务组件&#xff0c;一个是 通道错误码组件&#xff0c;一个是 审核流水组件。 这两个业务组件都要依赖Mybatisplus来操作数据。 com.sby.bizcomponent├── auditflow│ └── A…

t015-预报名管理系统设计与实现 【含源码!!!】

项目演示地址 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装预报名管理系统软件来发挥其高效地信息处理的…

数学建模之最短路径问题

1 问题的提出 这个是我们的所要写的题目&#xff0c;我们要用LINGO编程进行编写这个题目&#xff0c;那么就是需要进行思考这个怎么进行构建这个问题的模型 首先起点&#xff0c;中间点&#xff0c;终点我们要对这个进行设计 2 三个点的设计 起点的设计 起点就是我们进去&am…

刀具问题讨论

1 刀具的问题概述 问题描述 一道工序用自动化车床连续加工某种零件&#xff0c;由于刀具损坏等原因该工序会出现故障&#xff0c;其中刀具损坏故障占95%, 其它故障仅占 5%。工序出现故障是完全随机的, 假定在生产任一零件时出现故障的机会均相同。工作人员通过检查零件来确定…

stm32 / arduino TPL0401A使用教程

这是在给英国的一个学生讲课时用到的一个芯片&#xff0c;做一个dcdc的反馈电路&#xff0c;刚开始用的不是这个&#xff0c;后来发现国内这个芯片用的挺成熟&#xff0c;就选择了这个。 芯片说明 首先我买的是TPL0401A,我发现淘宝上卖的都是A&#xff0c;其实想用C&#xff0…

进程调度策略和进程优先级

Linux 的进程调度策略和进程优先级是操作系统为保证系统响应性、公平性和高性能所设计的关键机制。 进程调度策略 Linux 支持 两大类调度策略&#xff1a; 普通调度策略&#xff08;CFS: Completely Fair Scheduler&#xff09;&#xff0c; 适用于大部分用户态进程。实时调…