【Linux】命令行参数与环境变量

在 Linux 系统的学习与开发中,命令行参数环境变量是两个极为重要的概念,它们是程序与系统、程序与用户交互的关键桥梁。本文将从基本概念入手,逐步深入,结合代码示例详细解析这两个知识点。


一、环境变量:操作系统的"运行参数"

(一)基本概念

环境变量(environment variables)是操作系统中用来指定运行环境的参数集合。它有以下几个关键特性:

  • 特殊用途:比如在编译 C/C++ 程序时,链接器依靠环境变量查找动态 / 静态库,我们无需手动指定库路径也能完成链接。
  • 全局特性:在系统中具有全局性,影响范围广泛。

(二)常见环境变量

Linux 系统中有许多预定义的环境变量,以下是最常见的几个:

|----------|--------------------------------------|---------------------------------------------------|
| 环境变量 | 作用 | 示例 |
| PATH | 指定命令的搜索路径,系统会按该路径顺序查找可执行程序 | /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin |
| HOME | 指定用户的主工作目录,即用户登录系统后的默认目录 | 普通用户为/home/xxx,root 用户为/root |
| SHELL | 指定当前使用的 Shell,Linux 默认通常是/bin/bash | /bin/bash |

(三)查看环境变量的方法

最直接的方式是使用 echo命令,格式为echo $变量名。

  • 单变量查看:echo $变量名,如echo $PATH
  • 批量查看:env显示所有环境变量;set显示本地 Shell 变量和环境变量。

(四)举例

1、PATH环境变量测试

将以上简单的代码编译成可执行程序后,我们来对比两种执行方式:

  • 带路径执行:./hello
  • 直接执行:hello

问题来了,为什么系统命令(如lscd)可以直接执行,而我们的hello程序必须带路径?

那是因为系统命令的可执行文件位于PATH环境变量指定的路径中,系统会自动搜索;而hello所在路径不在PATH中,所以必须手动指定路径。

所以我们可以试试将程序路径加入PATH:

bash 复制代码
export PATH=$PATH:程序实际所在路径

直接执行hello,此时程序可以正常运行。

2、HOME环境变量测试

  • root 用户执行:echo $HOME,输出/root
  • 普通用户执行:echo $HOME,输出/home/xxx(xxx 为用户名)。

如下图,执行cd ~; pwd,输出的路径与$HOME的值一致,说明~是HOME的简写。

(五)与环境变量相关的命令

|--------|------------------------|
| 命令 | 功能 |
| echo | 显示单个环境变量的值 |
| export | 设置新的环境变量(或导出已有变量为环境变量) |
| env | 显示所有环境变量 |
| unset | 清除环境变量 |
| set | 显示本地定义的 Shell 变量和环境变量 |

(六)环境变量的组织方式

每个程序都会收到⼀张环境表,环境表是⼀个字符指针数组,每个指针指向⼀个以'\0'结尾的环境字符串。

(七)通过代码获取环境变量

在 C 语言中,有两种常见方式获取环境变量。

方式 1:通过main函数的第三个参数

main函数可以接收第三个参数char *env[],它指向环境变量表。

cpp 复制代码
#include <stdio.h>

int main(int argc, char *argv[], char *env[])
{
    int i = 0;
    for(; env[i]; i++){
        printf("%s\n", env[i]);
    }
    return 0;
}

运行的结果和使用env命令一样。

方式 2:通过全局变量environ

cpp 复制代码
#include <stdio.h>

int main(int argc, char *argv[])
{
    extern char **environ;

    int i = 0;
    for(; environ[i]; i++){
        printf("%s\n", environ[i]);
    }
    return 0;
}

libc中定义了全局变量environ,它指向环境变量表。由于environ未包含在头文件中,使用时需用extern声明。

(八)通过系统调用获取或设置环境变量

Linux 提供了系统调用函数来获取或设置环境变量,常用的有 getenv和 putenv(后面讲解)。

函数getenv:获取指定环境变量的值

函数原型:char *getenv(const char *name);

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>  // getenv需要的头文件
int main()
{
    printf("%s\n", getenv("PATH"));
    return 0;
}

(九)环境变量的全局属性

环境变量具有全局属性可以被子进程继承。我们通过一个例子来验证这一点。

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *env = getenv("MYENV");
    if(env){
        printf("%s\n", env);
    }
    return 0;
}

直接运行程序,无输出(因为MYENV环境变量不存在)。

此时我们导出环境变量MYENV:

bash 复制代码
export MYENV="hello world"

再次运行程序:

说明子进程(我们的程序)继承了父进程(Shell)的环境变量。

但当我们执行MYENV="hello world"(不export)时,这个变量仅属于当前 Shell 的本地变量 (Local Variable),其作用域仅限于当前 Shell 进程本身,不会被子进程(例如我们编译的 C 程序)继承。

原理分析:

  • Shell 进程在创建子进程时,会将自己的环境变量 (通过 export 声明的变量)复制一份传递给子进程,但本地变量不会被复制。
  • 因此,直接执行 MYENV="hello world" 后运行程序,子进程中无法获取 MYENV;而通过 export MYENV="hello world" 声明后,MYENV 成为环境变量,才能被子进程继承。

(十)环境变量的持久化设置

临时通过 export 设置的环境变量,会在当前 Shell 关闭后失效。若需环境变量永久生效(系统重启后仍可用),需修改系统配置文件,具体分为以下两种场景:

  • 对所有用户生效(全局设置)

修改 /etc/profile/etc/environment 文件(需 root 权限),所有用户登录后均可使用该环境变量。(以修改 /etc/profile 为例)

1、使用 root 权限打开文件

bash 复制代码
sudo vim /etc/profile

2、在文件末尾添加环境变量声明

bash 复制代码
export MYENV="hello world"  # 格式:export 变量名=值(值若含空格需用引号包裹)

3、无需重启,执行以下命令让系统重新加载配置文件:

bash 复制代码
source /etc/profile
  • 仅对当前用户生效(局部设置)

修改当前用户主目录下的 ~/.bashrc~/.bash_profile 文件(无需 root 权限),仅当前用户可使用该环境变量。(以修改 ~/.bashrc 为例)

1、打开文件

bash 复制代码
vim ~/.bashrc  # 或 gedit ~/.bashrc

2、在文件末尾添加环境变量声明

bash 复制代码
export MYENV="hello world"

3、使配置立即生效

bash 复制代码
source ~/.bashrc  # 重新加载当前用户的配置文件

注意事项:

  • 配置文件中的环境变量声明必须带 export,否则仅为文件所在 Shell 的本地变量,无法被子进程继承。
  • 若同时修改了全局和局部配置文件,局部配置会覆盖全局配置 (优先级:~/.bashrc > ~/.bash_profile > /etc/profile)。
  • 对于 ~/.bash_profile~/.bashrc 的区别:
    • ~/.bash_profile 仅在用户登录时加载 (如通过 ssh 登录或图形化界面登录);
    • ~/.bashrc每次打开新的终端窗口时加载,更适合日常临时添加的环境变量,推荐优先使用。

二、命令行参数

(一)基本概念

命令行参数是用户在启动程序时,通过命令行传递给程序的参数 ,用于控制程序的行为、指定输入输出等。例如ls -l /home中,-l/home都是ls命令的命令行参数。

(二)命令行参数在 C 程序中的表示

想必大家对这两个参数都很眼熟,但是我们并不知道是干什么用的。

C 程序通过main函数的前两个参数接收命令行参数

  • int argc参数个数(argument count),包含程序名本身。
  • char *argv[]参数数组 (argument vector),每个元素是一个参数字符串,argv[0]是程序名,argv[1]argv[argc-1]是用户传入的参数。

例如:

cpp 复制代码
#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;
}

三、命令行参数与环境变量的区别与联系

|----------|----------------------------|---------------------------------|
| 对比项 | 命令行参数 | 环境变量 |
| 作用域 | 仅对当前启动的程序有效 | 具有全局属性,可被子进程继承 |
| 传递时机 | 程序启动时通过命令行传递 | 程序启动前已由系统或用户设置 |
| 修改方式 | 需重新启动程序并传入新参数 | 可通过export、修改配置文件等方式动态修改(或持久化) |
| 联系 | 两者都是程序与外部交互的方式,共同决定程序的运行行为 | |

相关推荐
wangjialelele8 小时前
Qt中的常用组件:QWidget篇
开发语言·前端·c++·qt
九德拉8 小时前
利用XPlaneConnect从X-Plane内读写数据
c++·飞行仿真·x-plane
j_xxx404_9 小时前
Linux:权限复盘扩展|粘滞位|软件包管理器|Linux软件生态
linux·1024程序员节
_OP_CHEN9 小时前
C++进阶:(三)深度解析二叉搜索树原理及实现
开发语言·数据结构·c++·二叉树·二叉搜索树·键值对
xflySnail9 小时前
内网穿透方案-nps
linux·服务器·内网穿透·nps
QiTinna9 小时前
Linux运维核心命令(入门)
linux·运维·服务器
初听于你10 小时前
LoRa与ZigBee:物联网双雄对决
服务器·网络·windows·网络协议·计算机网络
哦你看看10 小时前
Redis Sentinel哨兵集群
linux·redis·bootstrap·sentinel
郝学胜-神的一滴11 小时前
深入解析C++命令模式:设计原理与实际应用
开发语言·c++·程序人生·软件工程·命令模式