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

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.xdnf.cn/news/2238.html

    相关文章:

  • xVerify:推理模型评估的革新利器,重塑LLM答案验证格局?
  • OpenFeign 快速开始
  • C++:string 1
  • YTJ笔记——FFT、NCC
  • Maven的聚合工程与继承
  • Pygame动画实战:让游戏角色动起来!
  • Java24 抗量子加密:后量子时代的安全基石
  • 华为盘古OS深度评测:构建AI自进化系统的实践密码
  • 第一性原理 | 从哲学本源到多领域实践的探索与应用
  • 腾讯二面:TCC分布式事务 | 图解TCC|用Go语言实现一个TCC
  • MyBatis 常用扩展组件详解(含代码示例)
  • 有源晶振与无源晶振详解:区别、应用与选型指南
  • 计算机视觉中的二值马尔科夫随机场
  • 代码随想录算法训练营第五十九天 | 1.ford算法精讲 卡码网94.城市间货物运输
  • 长短板理论——AI与思维模型【83】
  • 如何在 Windows 10 中使用 WSL 和 Debian 安装 Postgresql 和 Postgis
  • Vue3的内置组件 -实现过渡动画 TransitionGroup
  • 计算机二级MS Office第九套演示文稿
  • 隐私守护者的觉醒——大数据时代,我们如何对抗“透明人”危机?
  • 单链表专题(1)
  • 豆包,Kim,deepseek对比
  • Java——令牌技术
  • Oracle EBS 零金额的AP付款无法过账数据修复
  • 蓝桥杯赛场反思:技术与心态的双重修炼
  • 基于libdxfrw库读取样条曲线并离散为点
  • 在Linux虚拟机下使用vscode,#include无法跳转问题
  • 前端开发中shell的使用场景
  • 部署yolo到k230教程
  • cloud项目同一个服务,执行不同业务需求,nacos进行分组
  • 数据结构之单链表C语言