Linux进程(四)概念:命令行参数和环境变量篇

在 Linux 编程、Shell 开发里,命令行参数 和 环境变量 是进程和外部传递信息的两种核心方式。命令行参数是程序启动时一次性传给程序的参数;环境变量附着在进程上,是一组全局的键值对,子进程默认继承父进程的环境变量。现在我们一起从概念、命令、内核组织、系统调用、代码示例梳理该部分知识点。

目录

[一、 概念](#一、 概念)

[1. 命令行参数](#1. 命令行参数)

[2. 环境变量](#2. 环境变量)

二、环境变量

1.常见的环境变量

2.查看环境变量的方法

3.shell命令

[4. 环境变量在进程中的组织方式](#4. 环境变量在进程中的组织方式)

[5. 程序中获取环境变量的两种方式](#5. 程序中获取环境变量的两种方式)

[方式 1:main 函数第三个参数 env](#方式 1:main 函数第三个参数 env)

[方式 2:全局变量 environ(不需要改 main 形参)](#方式 2:全局变量 environ(不需要改 main 形参))

[6. 库函数 / 系统调用:获取、设置环境变量](#6. 库函数 / 系统调用:获取、设置环境变量)

[6.1 getenv:获取指定环境变量](#6.1 getenv:获取指定环境变量)

[6.2 setenv:设置环境变量](#6.2 setenv:设置环境变量)

[6.3 putenv:设置环境变量](#6.3 putenv:设置环境变量)

[6.4 unsetenv:删除环境变量](#6.4 unsetenv:删除环境变量)

[6.5 clearenv:清空当前进程所有环境变量](#6.5 clearenv:清空当前进程所有环境变量)

[7. 特性:环境变量是进程内全局属性](#7. 特性:环境变量是进程内全局属性)

三、总结



一、 概念

1. 命令行参数

程序启动时,在命令行后跟的参数,传递给 main 函数。 C 语言标准 main 写法:

复制代码
int main(int argc, char* argv[]);

argc(argument count):参数个数,程序本身也算一个参数

argv(argument vector):字符串指针数组,argv[0] 是程序名,argv[1] 是第一个参数,argv[argc] = NULL 作为结束标记

示例:./test aaa bbb

argc = 3

argv0 = "./test"

argv1 = "aaa"

argv2 = "bbb"

命令行参数只在本次启动生效,不会传给其他进程,也不是全局的。

2. 环境变量

环境变量是进程级别的全局键值对 ,格式:KEY=VALUE。 作用:给进程提供全局配置、运行上下文。 典型特点:

父进程创建子进程时,子进程默认继承父进程全部环境变量;

环境变量修改默认只在当前进程内生效,不影响父进程;

是进程的运行上下文,Shell、编译工具、程序都依赖它。

重点:环境变量是进程内全局,不是操作系统全局。不同进程可以有不一样的环境变量,修改子进程环境变量不会改父进程。


二、环境变量

1.常见的环境变量

表格

变量名 含义
PATH 命令搜索路径,Shell 找可执行文件时,按 PATH 里的目录依次查找
HOME 当前用户家目录
USER 当前登录用户名
PWD 当前工作目录(和 getcwd 对应,之前代码里用到)
OLDPWD 上一次的工作目录,cd - 依赖它
SHELL 当前使用的 Shell 程序,一般是 /bin/bash
LD_LIBRARY_PATH 动态链接库搜索路径
LANG 语言编码、字符集

2.查看环境变量的方法

env:列出当前进程所有环境变量

printenv:和 env 几乎一样,打印环境变量

echo $VAR:查看单个环境变量

复制代码
echo $PATH
echo $PWD

set:不仅打印环境变量,还会打印 Shell 本地变量(本地变量≠环境变量,不会被子进程继承)

区分:环境变量 可以被子进程继承;Shell 本地变量只在当前 Shell 有效,子进程看不到。

3.shell命令

  1. export VAR=xxx:把本地变量导出为环境变量,子进程可以继承

或

  1. unset VAR:删除环境变量
  1. export 不带参数:查看所有被导出的环境变量

4. 环境变量在进程中的组织方式

Linux 中,每个进程有自己独立的环境表,本质是一个char* 指针数组 ,数组最后一个元素是 NULL 标记结束。 C 语言 main 函数完整三参数版本:

cpp 复制代码
int main(int argc, char* argv[], char* env[]);

env 就是环境表:

复制代码
env[0] = "PATH=/usr/bin:/bin";
env[1] = "HOME=/home/xxx";
env[2] = "PWD=/root";
...
env[n] = NULL;

在进程的地址空间中:

命令行参数、环境变量字符串,都放在进程栈区上方的环境区;

内核创建进程时,会把父进程的环境表拷贝一份给子进程;

环境表指针 environ 是一个全局外部变量,所有 C 程序都可以使用。

全局变量声明:extern char** environ; 这个 environ 和 main 的第三个参数 env 指向同一块环境表。

5. 程序中获取环境变量的两种方式

方式 1:main 函数第三个参数 env

cpp 复制代码
#include <stdio.h>
int main(int argc, char* argv[], char* env[])
{
    for(int i = 0; env[i]; i++)
    {
        printf("%s\n", env[i]);
    }
    return 0;
}

结果如下:

方式 2:全局变量 environ(不需要改 main 形参)

cpp 复制代码
#include <stdio.h>
extern char** environ;
int main()
{
    for(int i = 0; environ[i]; i++)
    {
        printf("%s\n", environ[i]);
    }
    return 0;
}

结果如下:

6. 库函数 / 系统调用:获取、设置环境变量

getenv / setenv / putenv 是 C 标准库函数,底层封装了对进程环境表的操作,不是直接系统调用;真正的系统调用是 exec 系列、fork 等。

6.1 getenv:获取指定环境变量

头文件 <stdlib.h>

cpp 复制代码
char *getenv(const char *name);

传入变量名,返回对应值的指针;找不到返回 NULL。

不修改环境表。

6.2 setenv:设置环境变量

cpp 复制代码
int setenv(const char *name, const char *value, int overwrite);

overwrite=1:如果变量已经存在,覆盖旧值;

overwrite=0:已存在则不修改;

函数内部会自己分配内存存放字符串,没有悬空指针风险。

6.3 putenv:设置环境变量

cpp 复制代码
int putenv(char *string);

参数格式必须是 KEY=VALUE;

不会拷贝字符串!直接保存传入指针的地址

如果传入栈上局部数组,函数退出后栈回收,环境变量变成野指针,程序崩溃。 就是你之前 GetPwd 代码里的那个坑!

6.4 unsetenv:删除环境变量

cpp 复制代码
int unsetenv(const char *name);

6.5 clearenv:清空当前进程所有环境变量

cpp 复制代码
int clearenv(void);

7. 特性:环境变量是进程内全局属性

环境变量在当前进程内部是全局可见的,进程内所有函数都可以调用 getenv/setenv 访问;但是默认只在当前进程和它的子进程生效,对父进程、其他无关进程没有任何影响。

fork 创建子进程:子进程拷贝一份父进程环境表;父子后续修改互相独立;

exec 加载新程序:默认继承当前进程环境表;

想修改父进程的环境变量:普通子进程做不到,Shell 里只有内置命令(cd、export)才会直接修改 Shell 本身环境,外部程序无法修改父 Shell 环境。


三、总结

Linux 下命令行参数 与环境变量 ,二者是进程接收外部信息的两大途径:命令行参数是程序启动时一次性传入的参数;环境变量是附着在进程上的KEY=VALUE键值对,子进程默认继承父进程环境变量。

  1. 命令行参数 :依靠 argc(参数个数)、argv(参数字符串数组)传递,argv[0]代表程序名,仅本次程序运行有效,不具备继承性。
  2. 环境变量基础 :属于进程内全局,不是操作系统全局,修改子进程环境不会影响父进程;列举了PATH、HOME、PWD等常用环境变量。
  3. Shell 操作命令 :使用env / printenv / echo $变量名 / set查看;export导出环境变量、unset删除变量,export、unset、cd属于 Shell 内置命令,不能搭配 sudo 执行。
  4. 底层组织形式 :环境表是char*指针数组,以NULL收尾;可以通过 main 第三个参数env或者全局外部变量environ遍历环境表。
  5. C 语言库函数 (头文件<stdlib.h>)
    • getenv:读取指定环境变量;
    • setenv:安全设置变量,内部自动管理内存;
    • putenv:直接保存传入字符串指针,传入栈数组会造成野指针风险;
    • unsetenv删除单个变量、clearenv清空全部环境变量。
  6. 核心特性:fork 出的子进程会拷贝父进程环境表,父子后续修改互不干扰;exec 加载程序默认继承环境;外部可执行程序无法修改父 Shell 的环境,只有 Shell 内置命令可以修改 Shell 自身环境。
相关推荐
承渊政道27 分钟前
Linux网络学习【深入理解多路转接select、poll的代码改写】
linux·ubuntu·select·多路转接·poll
方便面不加香菜29 分钟前
Docker Container -- 容器命令详解
运维·docker·容器
NextTech_32 分钟前
不想学 vim,怎么改服务器上的配置文件?
服务器·编辑器·vim
qq_377572771 小时前
linux x86 arm loongarch
linux
Dragon~Snow1 小时前
Centos Stream10 安装 MySQL-9.7.2-linux-glibc2.28-x86_64.tar
linux·mysql·centos
say_fall1 小时前
【Linux系统编程】Linux进程信号:从“外卖到了“到内核里的一张位图
linux·运维·服务器·车载系统·智能硬件
Z21-X2 小时前
云原生运维实战笔记:企业网站综合上云部署与云运维服务全景解析
运维·笔记·学习·云原生
坤坤子吖2 小时前
Linux网络编程:UDP进阶,从字典服务器到简单聊天室
linux·服务器·网络·c++·笔记·学习
Rabitebla2 小时前
【Linux学习笔记】进程篇(九):进程的创建与退出——fork、写时拷贝与退出码
linux·c++·笔记·学习