Linux操作系统从入门到实战(二十二)命令行参数与环境变量

发布于:2025-08-16 ⋅ 阅读:(11) ⋅ 点赞:(0)


前言

上一篇博客中,我们介绍了进程切换与进程调度;

  • 这一篇,我们将讲解命令行参数与环境变量

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482


一、命令行参数

  • 你有没有好奇过:
  • 当我们在Linux终端输入 ls -l 或者 cp file1.txt file2.txt 时,程序是怎么知道我们后面输入的 -lfile1.txt 是什么意思的?

在这里插入图片描述

这些跟在命令后面的“附加信息”,其实就是命令行参数

1. 程序怎么知道我们在命令行输入了什么?

  • 比如我们写了一个C语言程序,编译后生成可执行文件 test,然后在终端运行 ./test hello 123
  • 程序怎么知道我们输入了 hello123 呢?

这就要靠C语言中 main 函数的两个特殊参数:argcargv

2. main 函数的参数 argc 和 argv 到底是什么?

我们平时写 main 函数可能会简化成 int main(),但其实它的标准形式是这样的:

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

这两个参数专门用来接收命令行输入的信息

  • argc(Argument Count):简单说就是“参数的总个数”。
    注意:它会把程序本身的路径也算作一个参数。
    比如运行 ./test hello 123 时,输入的内容有3个部分:./test(程序本身)、hello123,所以 argc = 3

  • argv(Argument Vector):可以理解为“参数的具体内容”,它是一个字符串数组(存放了所有参数的文本)。

    • argv[0] 永远是程序自己的路径或名字(比如 ./test);
    • argv[1] 是第一个用户输入的参数(比如 hello);
    • argv[2] 是第二个用户输入的参数(比如 123);
    • 以此类推,最后一个元素是 NULL(表示数组结束)。

3. 用代码实际看看它们的值?

我们写一个简单的程序,把所有参数都打印出来:

#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]);
    }
    
    return 0;
}

编译运行试试:

  1. 保存为 test.c,用 gcc test.c -o test 编译生成 test 可执行文件;
  2. 在终端输入 ./test hello world 2025,输出会是这样:
总共有 4 个参数
第 0 个参数:./test
第 1 个参数:hello
第 2 个参数:world
第 3 个参数:2025

在这里插入图片描述

4. 这些参数有什么实际用处?

我们平时用的Linux命令,本质上也是程序,它们就是通过 argcargv 来处理我们输入的参数的。

比如:

  • 输入 ls -l 时,ls 程序的 argc=2argv[1] = "-l",程序看到 -l 就知道要“以详细列表形式显示文件”;
  • 输入 cp a.txt b.txt 时,cp 程序的 argc=3argv[1] = "a.txt"argv[2] = "b.txt",所以它知道要把 a.txt 复制成 b.txt

二、环境变量:

  • 在终端输入 ls 就能执行列表命令,输入 gcc 就能编译代码,为什么不用写全它们的安装路径(比如 /bin/ls)?
  • 还有,系统怎么知道你的用户名是什么、家目录在哪里?
  • 这些背后其实都和“环境变量”有关

1. 为什么输入 ls 就能运行,不用写全路径?

比如 ls 这个命令,实际安装在 /bin/ls 路径下,但我们不用输入 /bin/ls,直接敲 ls 就行。这是谁在帮我们“找”到程序的位置?

  • 答案就是 环境变量 里的 PATH
  • 简单说,环境变量就像系统里的“全局记事本”,记录着各种程序运行时需要的配置信息,PATH 就是其中之一——它里面存着一串目录(用冒号分隔),
  • 系统会在这些目录里自动搜索你输入的命令

2. 什么是环境变量?为什么需要它?

环境变量 可以理解为“进程运行时的全局配置信息”,本质是一堆“键值对”(比如 KEY=VALUE)。

它的核心作用有两个:

  • 解耦路径依赖:就像 PATH 变量,不用硬记每个程序的安装路径,系统会自动按 PATH 里的目录找程序(比如 lsgcc 都在 PATH 包含的目录里)。
  • 传递全局状态:比如 USER 变量存着当前用户名(输入 echo $USER 能看到),HOME 存着你的家目录(echo $HOME 显示 /home/你的用户名),LANG 控制语言编码……这些信息让不同程序能“统一认知”系统状态。

3. 在终端里怎么查看环境变量?

很简单,有两个常用命令:

  • 看单个变量:echo $变量名。比如想知道 PATH 里有哪些路径,输入 echo $PATH,会输出类似这样的内容(不同系统可能有差异):
    在这里插入图片描述

    /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    
  • 看所有变量:输入 env,会列出系统里所有环境变量(比如 USER=xxxTERM=xterm 等)。

4. 如果我写C程序,想拿到环境变量的值,该怎么做?

  • C语言提供了3种方式访问环境变量,重点记前两种就行:

方式1:用 getenv 精准查找(最常用)

getenv 就像“按名字查字典”,给它变量名,它返回对应的值。比如查 PATH

#include <stdio.h>
#include <stdlib.h> // 必须包含这个头文件

int main() {
    // 查找名为"PATH"的环境变量
    char *path_value = getenv("PATH");
    
    if (path_value != NULL) {
        printf("PATH里的路径:%s\n", path_value);
    } else {
        printf("没找到PATH变量!\n");
    }
    
    return 0;
}

编译运行后,就能看到和 echo $PATH 一样的内容。

方式2:用 environ 全局变量枚举所有变量

environ 是系统自带的全局变量,它指向一个数组,里面存着所有环境变量(格式都是 KEY=VALUE)。比如遍历所有变量:

#include <stdio.h>

// 声明environ全局变量(系统已经定义好了)
extern char **environ;

int main() {
    // 遍历数组,直到遇到NULL(数组结束标志)
    for (int i = 0; environ[i] != NULL; i++) {
        printf("环境变量[%d]:%s\n", i, environ[i]);
    }
    
    return 0;
}

运行后会打印出所有环境变量,和 env 命令的输出类似。

方式3:修改环境变量

如果想在程序里改环境变量,可以用 setenv(设置或覆盖)和 unsetenv(删除):

#include <stdlib.h>
#include <stdio.h>

int main() {
    // 设置一个新变量MY_NAME,值为"xiaobai",第三个参数1表示覆盖已存在的
    setenv("MY_NAME", "xiaobai", 1);
    printf("MY_NAME: %s\n", getenv("MY_NAME")); // 会输出xiaobai
    
    // 删除MY_NAME变量
    unsetenv("MY_NAME");
    printf("删除后MY_NAME: %s\n", getenv("MY_NAME")); // 会输出(null)
    
    return 0;
}

5. 环境变量和“本地变量”有啥区别?

在终端里,我们可能会用 A=123export B=456 设变量,但这两种不一样:

对比项 环境变量(用 export 声明) 本地变量(直接 KEY=VALUE
作用范围 当前进程和它启动的子进程都能读到 只有当前终端会话能读到,子进程读不到
举个例子 终端输入 export B=456,再运行C程序,用 getenv("B") 能拿到456 终端输入 A=123,运行C程序,getenv("A") 拿不到值

6. 环境变量的“全局”和“会话”是什么意思?

环境变量不是一成不变的,按影响范围分两种:

  • 全局环境变量:影响所有用户和所有进程,比如 /etc/environment 文件里的配置。系统级的程序(比如 lscp)的路径通常在这里配置,确保所有用户都能正常使用。

  • 会话环境变量:只影响当前用户的终端会话,比如 ~/.bashrc(bash终端的配置文件)里的内容。你可以在这里设自己的别名(比如 alias ll='ls -l')、自定义路径,只对自己生效。

注意:修改配置文件后,需要用 source ~/.bashrc(比如修改了 .bashrc)让配置立即生效,否则要重启终端才会生效。

7. 环境变量是怎么在进程之间“传递”的?

环境变量的传递规则很简单:

  1. 每个进程启动时,会复制一份父进程的环境变量(相当于“继承”)。比如终端(父进程)里的环境变量,你运行的C程序(子进程)能读到。
  2. 子进程修改自己的环境变量,不会影响父进程(副本之间互不干扰)。

8. 环境变量和之前说的“命令行参数”有啥不一样?

简单说,命令行参数是“临时指令”,环境变量是“全局配置”,对比表如下:

特性 命令行参数(比如 ls -l 中的 -l 环境变量(比如 PATH
作用 给程序传递一次性的输入(本次运行有效) 给程序传递全局配置(进程及子进程有效)
用法 运行程序时显式写在后面(./程序 参数 预先通过 export 或配置文件设置

举个例子:curl -X GET $API_URL 中,-X GET 是命令行参数(告诉curl用GET方法),$API_URL 是环境变量(全局配置接口地址,换个程序也能复用)。

三、命令行参数 vs 环境变量

特性 命令行参数 环境变量
传递目的 临时控制程序单次运行的行为(如参数、选项) 提供进程运行时的全局配置信息(如路径、密钥)
作用范围 仅对当前执行的程序实例有效,执行结束后失效 对当前进程及所有子进程有效(通过继承机制传递)
使用方式 运行程序时显式附加在命令后(如 python script.py --debug 预先通过 export 命令设置或写入配置文件(如 .bashrc
可见性 在进程列表(如 ps 命令)中可见,易被查看 需通过 printenv 或进程环境文件查看,相对隐蔽
持久性 完全临时,仅随当前命令执行存在 可临时(当前shell会话)或持久(配置文件)存在
继承性 不会被子进程自动继承,需显式传递给子进程 子进程会自动继承父进程的环境变量
数据量适配 适合传递少量、简单的参数(如选项、路径) 适合传递多组配置信息(如多个服务地址、密钥)
典型示例 ls -l 中的 -lcurl -o file.txt 中的 -o file.txt PATH(可执行文件路径)、HOME(用户主目录)、API_KEY(接口密钥)

以上就是这篇博客的全部内容,下一篇我们将继续探索Linux的更多精彩内容。

我的个人主页
欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的Linux知识文章专栏
欢迎来阅读指出不足
https://blog.csdn.net/2402_83322742/category_12879535.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到