linux系统之----命令行参数和环境变量

一、命令行参数

1.main()函数的参数

在C语言中,main函数可以接收命令行参数,其标准形式为:

int main(int argc, char *argv[]) {// 程序代码return 0;
}

这里我们解释一下:

argc:参数个数计数器(Argument Count),表示命令行参数的个数,包括程序名称本身。它是一个整数,值至少为1(因为程序名称本身算一个参数)。

argv:参数值数组(Argument Vector),是一个指向字符数组的指针数组,每个元素指向一个以null结尾的字符串,这些字符串就是命令行参数。argv[0]通常是程序的名称,argv[1]argv[argc - 1]是用户提供的参数,argv[argc]NULL换句话说,argv的最后一个一定是NULL,其余的元素由用户指定!

代码测试:

假设我们创建一个文件demo.c,并写入如下内容:

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

 写完之后保存并编译,并对上文内容进行测试,如下图所示:

 

倘若我们多试几个参数呢?

 

再测试一组:

    由此可见,argv[i]为什么是根据用户的空格分开的内容决定的。

    最后三句话总结:

    1.命令行参数,至少一个

    2.进程对应的程序的名字,一般是argv[0]

    3.有几个字串,argc就是几,记得用空格隔开

    2. 设计这个东西有什么用?

     命令行参数让程序可以根据用户输入的参数灵活地执行不同的操作,增强了程序的通用性和灵活性。例如,不同的参数可以触发程序的不同功能。

    根据参数执行不同功能

    我们看如下代码:

    #include <stdio.h>
    #include <string.h>int main(int argc, char *argv[]) {if (argc != 2) {printf("usage wrong!用法: %s <参数>\n", argv[0]);return 1;}if (strcmp(argv[1], "start") == 0) {printf("开始任务...\n");} else if (strcmp(argv[1], "stop") == 0) {printf("停止任务...\n");} else if (strcmp(argv[1], "status") == 0) {printf("任务状态: 运行中\n");} else {printf("未知参数: %s\n", argv[1]);}return 0;
    }

    我们将其保存并编译一下,并进行代码测试:

    那么好了,今天我写的是简易的代码,就输出的是字符串,那明天我能不能就把linux指令按照此例复刻出来呢?例如-l -a等等, 那换句话说,我们之前学的一些Linux指令本质就是一段程序,而我们-l   -a   等等这些选项,究其本质,就是一个一个的字符串,可以以一定的方式传递给你ls内部的main,在ls内部实现的时候,就可以根据不同的选项,实现类似功能的不同表现形式。

    二、环境变量

    1.定义:

    是系统级别的全局变量,具备不同的用途

    2.常见的环境变量

    2.1 PATH

    作用:用于定义系统查找可执行文件的路径。它是一个由冒号分隔的路径列表,系统会按照这个顺序在这些路径中查找命令的可执行文件。

    所以说,操作系统查找可执行命令,是在环境变量 PATH中查找的,如何证明呢?

    我们发现ls在路径usr/bin下,而echo &PATH包含这一路径,由此得以证明 

    2.2 HOME

    作用:指定当前用户的主目录路径。对于用户名为 username 的用户,HOME 的值通常是 /home/username

     2.3 SHELL

    作用:指定当前用户使用的 shell 程序的路径。

     

    2.4 找不到可执行程序

     三、获取环境变量

    1.通过 main 函数获取环境变量

    实际上,main函数是有三个参数的,其原型如下:

    int main(int argc, char *argv[], char *envp[])

    前两个参数解释过了,不再解释了,这里仅解释第三个参数:

    envp:是一个指向字符串数组的指针,说白了是个指针数组,数组里面存的一堆指针,这些字符串是环境变量,每个环境变量的格式为 KEY=VALUE

    1.1 环境变量表

    我们输入env,之后会弹出来一坨东西,(可能一瞬间有点绝望哈),好,我们看如下几个参数:

    这里我就按照老师的板书截出来了一部分,好奇的可以自己试一下去,命令env就是看环境变量的意思。

    好,现在我们回到环境变量表上,我们main函数的第三个参数指向就是这个环境变量表,那这个环境变量表到底长什么样子呢?

    环境变量表的结构

    字符串数组形式:环境变量表本质上是一个字符串数组,每个字符串表示一个环境变量,格式为 KEY=VALUE。例如,PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,其中 PATH 是键,/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 是值。

    以NULL结尾:环境变量表以空指针(NULL)结尾,表示表的结束。在 C 语言中,可以通过遍历这个数组直到遇到 NULL 来获取所有的环境变量。

    借用一下老师的板图,具体感受一下:

     用东北话讲就是一个萝卜一个坑,每个萝卜都是K=V的结构,最后一个坑啥也不种。

     

    2、通过函数获取单个环境变量

    可以使用 getenv() 函数来获取单个环境变量的值:

    我们输入man 3 getenv,得到如下内容(部分):

     

    说明: 

    name:是要获取的环境变量的名称。

    返回值:如果找到该环境变量,则返回一个指向其值的指针;如果没有找到,则返回 NULL

     代码示例:

    #include <stdio.h>
    #include <stdlib.h>int main() {char *path = getenv("PATH");if (path != NULL) {printf("PATH: %s\n", path);} else {printf("PATH not found\n");}return 0;
    }

    大家可以在xshell上自己试一下!感受一下~

    代码运行结果

    我们把那个PATH改一下改成PAHT看看结果

     显示路径不存在!

    环境变量查看实验成功!

    3.通过 environ 获取所有环境变量

    在 C 语言中,可以通过 extern char **environ 来访问所有的环境变量:

    #include <unistd.h>extern char **environ;

    environ 是一个指向字符串数组的指针,这些字符串是环境变量,每个环境变量的格式为 KEY=VALUE

    #include <stdio.h>
    #include <unistd.h>extern char **environ;int main() {for (char **env = environ; *env != NULL; env++) {printf("%s\n", *env);}return 0;
    }

    编译测试一下: 

     结果得到如下的一大堆:

    不要怕~这就是我们要查找的 所有环境变量

    查找成功!

    4.环境变量的获得

    实际上,我们运行程序或者进程时,并不是我的进程获得了环境变量,而是我的父进程(bash!!!)获得了环境变量,形成了上文所示的环境变量表,而我们的子进程是会继承父进程的代码和数据!例如,当你在终端中启动一个程序时,该程序会继承终端进程的环境变量。

    那么bash又是哪里来的环境变量呢?答案是从系统的配置文件中来!大家如果学习过ros在配置humble环境的时候应该频繁输入过bash或者bashrc等等诸如此类的代码,实际上就是在配置环境!

    不信的话,大家可以做一下~/.bash_profile && ~/.bashrc来修改文件级环境变量

    5. 为什么要有环境变量

    答案是不同的环境变量,会有不同的用途!!!

    如果我想写一个只有自己能执行的可执行程序呢?这个问题我们先保留。

    大家还记得pwd命令是什么吗?是用于显示当前工作目录的路径的,那是怎么显示的呢?

    实际上,进程会记录自己的工作路径(current working directory, cwd)。在 Linux 系统中,每个进程都有一个 task_struct 结构,其中保存了进程的 cwd。当创建子进程时,子进程会继承父进程的 task_struct,因此子进程的 cwd 与父进程相同。在 Bash shell 中,PWD 环境变量也会保存当前工作目录的路径。Bash 的 pwd 命令会从 PWD 环境变量中获取当前目录信息。

    所以说,我们的父进程bash的cwd也在task_struct里面保存着,我们的子进程自然而然的就继承了这个task_struct,所以说,我自己的pwd从哪里来?还是从bash来的!!

    那么,bash的pwd从哪里来呢

    5.1 getcwd函数

    getcwd 函数

    作用:用于获取当前工作目录的路径。

    函数原型:(输入man 3 getcwd获得)

    我们看如下代码: 

    #include <unistd.h>
    #include <stdio.h>int main() {char pwdbuf[128];char *pwd = getcwd(pwdbuf, sizeof(pwdbuf));printf("%s\n", pwd);return 0;
    }

    编译并运行一下,查看结果: 

      

     对比一下:

    因此,说明了getcwd 是用于获取当前工作目录的路径。换句话讲,bash的pwd也是通过getcwd函数获得的!

    四、环境变量的特点和总结

    1.环境变量的来源

    大部分环境变量来自系统的配置文件(如 /etc/profile/etc/environment)和用户的配置文件(如 ~/.bashrc~/.bash_profile)。少部分环境变量是启动后动态获取或创建的,例如 PWD 环境变量会在进程工作目录改变时动态更新。

    2. 环境变量的全局性

    环境变量具有全局属性,对当前进程及其所有子进程都有效。例如,在 Bash shell 中设置的环境变量会传递给通过该 shell 启动的所有子进程。

    但是,本地变量(local variable)只在父进程(如 Bash shell)内部有效,不会传递给子进程。

     传递不了,没有结果显示

    或者看这个例子也行,找出来那么多带“me"的进程,但是就是没有我要的那个”me"进程

     

    3.环境变量的动态性

    环境变量可以在运行时动态修改。例如,使用 export 命令可以临时修改环境变量。

    修改环境变量后,子进程会继承修改后的值。

    3.1 export详细解释

    1.基本概念

    在 Linux/Unix 系统中,export 是 shell 的一个内置命令,用于将变量或函数设置为环境变量。这意味着这些变量或函数不仅在当前 shell 会话中可用,还会被传递给其子进程。

    2.语法
    export [选项] [变量名=[值]]
    3.export 的选项

    -f:用于导出函数。

    -n:用于取消导出变量或函数。

    4.使用 export 出变量

     导出简单变量

    我们在xshell上面依次输入如下内容,观察现象:

    # 设置一个局部变量
    MY_VAR="Hello World"# 打印局部变量
    echo "In parent shell: $MY_VAR"  # 输出:In parent shell: Hello World# 启动一个子 shell,并尝试访问该变量
    bash -c 'echo "In child shell: $MY_VAR"'  # 输出:In child shell:# 使用 export 将变量导出为环境变量
    export MY_VAR# 再次启动一个子 shell,并访问该变量
    bash -c 'echo "In child shell: $MY_VAR"'  # 输出:In child shell: Hello World

    运行结果正确:

    在这个例子中,MY_VAR 最初是一个局部变量,仅在父 shell 中可用。使用 export 后,它变成了环境变量,子 shell 也可以访问它。说白了,就是把它给升级了,可以理解为export就是专升本考试,没export,只能在父进程里面用,export以后,升级了,子进程也可以用了! (个人观点,有不当之处可以评论区指出!)

    4.总结

    环境变量是系统和应用程序配置的重要组成部分,用于存储运行时需要的配置信息。

    环境变量可以通过多种方法获取,包括通过 main 函数的参数、getenv 函数和 environ 变量。

    环境变量具有全局性和动态性,可以在进程及其子进程中使用和修改。

    环境变量的初始化主要通过系统和用户的配置文件完成,少部分变量会在运行时动态获取或创建。

    五、内建命令

     1.定义

    内建命令(built-in command)是直接在 shell(如 Bash)内部实现的命令,而不是作为单独的可执行文件存在。它们是 shell 的一部分,因此执行时不需要创建新的子进程

    2、内建命令的特点

    执行效率高:由于内建命令在 shell 内部执行,不需要创建新的进程,因此执行速度更快。(不能创建子进程)

    可以直接访问和修改 shell 的内部状态:内建命令可以直接操作 shell 的环境变量、选项和其他内部状态。

    不需要子进程:内建命令在当前 shell 中执行,不会创建新的子进程。

    3.内建命令与普通命令的区别

    普通命令:大多数命令是可执行程序,存储在文件系统中(如 /bin/usr/bin 等目录)。执行时,shell 会创建一个新的子进程来运行这些命令。例如,lsgrep 等。

    内建命令:内建命令是 shell 内置的,直接在当前 shell 中执行。例如,cdexportecho 等。

    4.内建命令的示例

    1. echo 命令

    echo 是一个内建命令,用于输出文本或变量的值。

    在这个例子中,echo 直接在当前 shell 中执行,能够访问当前 shell 的环境变量 MYENV

    2. cd 命令

    cd 是一个内建命令,用于更改当前工作目录。

     3.其他命令

    实际上这样的命令还有很多,在这里我帮大家找了一些,大家可以看一看

    5、内建命令的执行机制

    当你在 shell 中输入命令时,shell 会先检查该命令是否为内建命令。如果是内建命令,shell 会直接在当前进程中执行它;如果不是内建命令,shell 会尝试在 PATH 环境变量指定的路径中查找可执行文件,并创建一个新的子进程来运行它。

     

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

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

    相关文章

    解析excel中的图片

    解析excel中的图片 前言一、pom依赖二、使用步骤1.示例数据2.代码如下&#xff08;示例&#xff09;&#xff1a; 总结 前言 初始化数据是&#xff0c;需要将excel中的数据解析并插入数据库。 但是某几列存放的是图片&#xff0c;这时候怎么办呢。 主要解决的是&#xff1a;获…

    Unity任务系统笔记

    数据结构设计 任务基类包括的字段&#xff1a; string 任务内容&#xff1b; Transform 任务目的地&#xff1b; MyCharacter 任务开启后要更新对话的NPC&#xff1b; MyTalkData 任务开启后相关NPC要说的对话数据&#xff1b; 共同方法&#xff1a;开启任务、完成任务。…

    STM32的开发环境介绍

    目录 STM32软件环境 Keil软件在线安装 其他软件环境安装 STM32开发的几种方式 STM32寄存器版本和库函数版本 标准外设库的作用&#xff1a; STM32软件环境 STM32 的集成开发环境&#xff08;IDE&#xff09;&#xff1a;编辑编译软件 常见的环境&#xff1a; (1)KEIL&a…

    【特殊场景应对9】视频简历的适用场景与风险分析

    写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…

    Linux系统性能调优技巧分享

    在数字化时代,Linux 系统以其开源、稳定、高效的特性,成为服务器、云计算、物联网等领域的核心支撑。然而,随着业务规模的扩大和负载的增加,系统性能问题逐渐凸显。掌握 Linux 系统性能调优技巧,不仅能提升系统运行效率,还能降低运维成本。下面从多个方面介绍实用的性能调…

    关于Code_流苏:商务合作、产品开发、计算机科普、自媒体运营,一起见证科技与艺术的交融!

    Code_流苏 &#x1f33f; 名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; &#x1f31f; 欢迎来到Code_流苏的CSDN主页 —— 与我一起&…

    系统架构设计(三):质量属性

    常见分类 一般来说&#xff0c;质量属性可以分为以下几类&#xff1a; 类别常见质量属性性能相关响应时间、吞吐量、资源利用率、实时性、可扩展性可用性相关可用性、高可用性&#xff08;HA&#xff09;、可靠性、容错性、恢复性可维护性相关可维护性、可测试性、可扩展性、…

    【锂电池剩余寿命预测】GRU门控循环单元锂电池剩余寿命预测(Matlab完整源码)

    目录 效果一览程序获取程序内容代码分享研究内容GRU门控循环单元在锂电池剩余寿命预测中的应用摘要关键词1. 引言1.1 研究背景1.2 研究现状与问题1.3 研究目的与意义2. 文献综述2.1 锂电池剩余寿命预测传统方法2.2 深度学习在锂电池寿命预测中的应用2.3 研究空白与本文切入点3.…

    SpringCloud原理和机制

    Spring Cloud 是一套基于Spring Boot的微服务开发工具集&#xff0c;它提供了在分布式系统环境下构建应用程序所需的一系列工具和服务。Spring Cloud旨在帮助开发人员快速构建一些常见的微服务模式&#xff0c;如服务发现、配置管理、智能路由、熔断器、微代理、控制总线等。 …

    LeetCode -- Flora -- edit 2025-04-25

    1.盛最多水的容器 11. 盛最多水的容器 已解答 中等 相关标签 相关企业 提示 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最…

    有关图的类型的题目以及知识点(2)

    1、具有5个顶点的有向完全图有20条弧。 2、若一个有向图用邻接矩阵表示&#xff0c;则第个结点的入度就是&#xff1a;第i列的非零元素的个数。 3、有向图的邻接矩阵可以是对称的&#xff0c;也可以是不对称的。 4、设N个顶点E条边的图用邻接表存储&#xff0c;则求每个顶点…

    正则表达式的捕获组

    是正则表达式中的一个重要概念&#xff0c;用于提取字符串中的特定部分 捕获组是通过正则表达式中的圆括号 () 定义的&#xff0c;它的作用是&#xff1a; 划分和标记&#xff1a;将正则表达式的一部分划分为逻辑单元。 提取数据&#xff1a;从字符串中提取符合组内模式的内容…

    deepseek-cli开源的强大命令行界面,用于与 DeepSeek 的 AI 模型进行交互

    一、软件介绍 文末提供程序和源码下载 deepseek-cli一个强大的命令行界面&#xff0c;用于与 DeepSeek 的 AI 模型进行交互。 二、Features 特征 Multiple Model Support 多模型支持 DeepSeek-V3 (deepseek-chat) DeepSeek-R1 &#xff08;deepseek-reasoner&#xff09;Dee…

    Java—— 五道算法水题

    第一题 需求&#xff1a; 包装类&#xff1a;键盘录入一些1~100之间的整数&#xff0c;并添加到集合中。直到集合中所有数据和超过200为止 代码实现&#xff1a; import java.util.ArrayList; import java.util.Scanner;public class Test1 {public static void main(String[]…

    安全编排自动化与响应(SOAR):从事件响应到智能编排的技术实践

    安全编排自动化与响应&#xff08;SOAR&#xff09;&#xff1a;从事件响应到智能编排的技术实践 在网络安全威胁复杂度指数级增长的今天&#xff0c;人工处理安全事件的效率已难以应对高频攻击&#xff08;如日均万级的恶意IP扫描&#xff09;。安全编排自动化与响应&#xf…

    网络原理 - 9

    目录 数据链路层 以太网 以太网帧格式 MAC 地址 DNS&#xff08;Domain Name System&#xff09; 完&#xff01; 数据链路层 这里的内容也是简单了解&#xff0c;除非是做交换机开发&#xff0c;一般程序员不需要涉及~~ 以太网 ”以太网“不是一种具体的网络&#xf…

    unity bug

    发现一个奇怪的bug&#xff0c;就是某些unity版本打包apk时候不允许StreamingAssets里面有中文文件或者中文路径。比如下图这面这俩都是不行的。 解决方案&#xff1a;中文改为英文即可。 一般报错信息如下&#xff1a; > Configure project :launcher WARNING:The option s…

    【Linux网络】打造初级网络计算器 - 从协议设计到服务实现

    &#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…

    计算机视觉——对比YOLOv12、YOLOv11、和基于Darknet的YOLOv7的微调对比

    概述 目标检测领域取得了巨大进步&#xff0c;其中 YOLOv12、YOLOv11 和基于 Darknet 的 YOLOv7 在实时检测方面表现出色。尽管这些模型在通用目标检测数据集上表现卓越&#xff0c;但在 HRSC2016-MS&#xff08;高分辨率舰船数据集&#xff09; 上对 YOLOv12 进行微调时&…

    ‌MySQL 事务隔离级别详解

    ‌ 以下是 MySQL 支持的四种事务隔离级别及其特性&#xff0c;按并发安全性从低到高排列&#xff1a; ‌1. 读未提交 (Read Uncommitted)‌ ‌问题‌&#xff1a; ‌脏读 (Dirty Read)‌&#xff1a;事务可读取其他事务未提交的数据。‌不可重复读 (Non-repeatable Read)‌&am…