八、命令行参数和环境变量

八、命令行参数和环境变量

8.1 命令行参数

main 函数其实是有参数的,main 函数的参数个数最多有3个

参数 类型 含义
argc(argument count) int 命令行参数的个数(包括程序名本身)。
argv(argument vector) char *argv[]char **argv 指向字符串数组的指针,每个字符串是一个命令行参数,最后一个元素为 NULL
envp(environment pointer) char *envp[]char **envp 指向环境变量字符串数组的指针,每个字符串格式为 "键=值",最后一个元素为 NULL

命令行参数是为了实现,一个命令可以根据不同的选项,实现不同的子功能 。这也是 Linux 中所有命令选项功能的实现方式。典型的声明形式例如:int main(int argc, char *argv[], char *envp[])

命令行参数的特点:

  • 命令行参数 argc >= 1argv[0] 一定有元素,指向的就是程序名。
  • 选项是以空格分隔的字符串,一个字符也是字符串。
  • argc 个,argv[argc-1] 是最后一个,argv[argc] == NULL

例如:

c 复制代码
#include <iostream>
#include <cstdio>
int main(int argc, char *argv[])
{
    std::cout << "argc: " << argc << std::endl;
    for(int i = 0; argv[i]; i++)
    {
        printf("i: %d  arg[v]: %s\n", i, argv[i]);
    }
    if(argv[argc] == nullptr)
    {
        printf(" == nullptr\n");
    }
        if (argc != 2)
    {
        printf("使用方法错误!示例:%s -a | -b | -c\n", argv[0]);
        exit(1);
    }

    // if (strcmp(argv[1], "-a") == 0)
    // {
    //     printf("正在执行第1种功能\n");
    // }
    // else if (strcmp(argv[1], "-b") == 0)
    // {
    //     printf("正在执行第2种功能\n");
    // }
    // else if (strcmp(argv[1], "-c") == 0)
    // {
    //     printf("正在执行第3种功能\n");
    // }
    // else if (strcmp(argv[1], "-d") == 0)
    // {
    //     printf("正在执行第4种功能\n");
    // }
    // else
    // {
    //     printf("正在执行默认功能\n");
    // }
    
    return 0;
}
// int argc : 参数的个数
// char *argv[] : 存储命令行参数
// char *envp[] : 环境变量表(传输给进程)

8.2 环境变量概念

环境变量 (Environment Variables)⼀般是指在操作系统中⽤来指定操作系统运行环境 的⼀些参数。环境变量通常具有某些特殊⽤途,不同的环境变量会有不同的应用场景。还有在系统当中通常具有全局特性

例如:在编写 C/C++ 代码时,链接的时候,并没有指定所要链接的动静态库在哪个目录,可还是链接成功并生成可执行程序了,其原因就是存在相关的环境变量帮助编译器查找库的位置。

示例:

一开始发现无法执行,因为没有指明路径。

./ 标识当前路径,简单来说就是告诉 OS,如果没有指明路径,用户要执行的程序就在当前路径下,而这个路径就存储在环境变量 PATH 中。

8.3 常见环境变量

常见环境变量 作用
PATH 可执行程序的搜索路径。
HOME 指定用户的主⼯作目录。
SHELL 当前 Shell,它的值通常是 /bin/bash
USER 当前用户名。

8.4 查看环境变量

指令

c 复制代码
echo $NAME
// NAME:环境变量名称
c 复制代码
#include <stdio.h>

int main()
{
    for (int i = 0; env[i]; i++)
    {
        printf("i: %d env[%d]: %s\n", i, i, env[i]);
    }
}

测试 PATH

为什么有些指令可以直接执⾏,不需要带路径,⽽我们的⼆进制程序需要带路径才能执⾏?

将我们的程序所在路径加⼊环境变量 PATH 当中:

临时添加export PATH=$PATH:程序所在路径

结束会话后失效。

永久添加

  1. 针对当前用户

编辑 ~/.bashrc~/.bash_profile 文件:

c 复制代码
// 打开配置文件
vim ~/.bashrc

// 在文件末尾添加
export PATH=$PATH:/your/program/path

// 保存后使配置生效
source ~/.bashrc
  1. 针对所有用户

编辑 /etc/profile/etc/environment

c 复制代码
// 打开配置文件
sudo vim /etc/profile

// 在文件末尾添加
export PATH=$PATH:/your/program/path

// 保存后使配置生效
source /etc/profile
  1. /etc/profile.d/ 中创建脚本
c 复制代码
// 创建自定义脚本
sudo vim /etc/profile.d/myprogram.sh

// 内容为
export PATH=$PATH:/your/program/path

// 保存后,该脚本会在下次登录时自动执行

8.5 环境变量相关命令

命令 作用
echo 显示某个环境变量值
export 设置⼀个新的环境变量
env 显示所有环境变量
unset 清除环境变量
set 显示本地定义的 shell 变量和环境变量

8.6 环境变量组织方式

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

8.7 环境变量通常具有全局属性

环境变量独立于程序本身,具有全局属性,可以被子进程继承。

shell 外壳 bash 的环境变量从哪里来?Linux 系统的配置文件。

本地变量私有 变量,只在当前脚本或 Shell 中有效,只具有局部属性。

c 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
int main(int argc, char *argv[], char *env[])
{
    char *myenv = getenv("MY_ENV") ;
    if(myenv)
    {
        printf("%s\n", myenv);
    }
    return 0;
}

直接查看,发现没有结果,说明该环境变量根本不存在。

导出环境变量 export MY_ENV="hello world"

再次运⾏程序,发现结果有了。说明:环境变量是可以被⼦进程继承下去的。

进程创建机制

当在 shell 中执行程序时,操作系统会使用 fork + exec* 系列函数:

  • fork:创建当前进程的副本(包括环境变量)
  • exec :用新程序替换当前进程的内容,但环境变量通常被保留
环境变量的存储结构
c 复制代码
// 每个进程都有这样的环境变量表
char *envp[] = {
    "PATH=/usr/bin:/bin",
    "HOME=/home/user",
    "MY_ENV=hello world",  // 你设置的环境变量
    NULL  // 结束标记
};
代码执行流程
c 复制代码
# shell进程
┌─────────────────┐
│ PATH=...        │
│ HOME=...        │
│ MY_ENV=hello    │ ← export在这里设置
└─────────────────┘
        │
        │ fork() 创建子进程
        ▼
┌─────────────────┐
│ PATH=...        │
│ HOME=...        │
│ MY_ENV=hello    │ ← 子进程继承所有环境变量
└─────────────────┘
        │
        │ exec() 执行你的程序
        ▼
┌─────────────────┐
│ 你的C程序       │
│ getenv("MY_ENV")│ ← 成功获取到值
└─────────────────┘
总结
  1. 继承机制: 子进程默认继承父进程的所有环境变量
  2. 单向性: 子进程对环境变量的修改不会影响父进程
  3. exec 保留: 即使程序被替换,环境变量表仍然保持
  4. 安全性: 这也是为什么敏感信息不应放在环境变量中的原因

8.8 获取环境变量

命令行第三个参数

c 复制代码
#include <iostream>
#include <cstdio>
int main(int argc, char *argv[], char *env[])
{
    for (int i = 0; env[i]; i++)
    {
        printf("i: %d env[%d]: %s\n", i, i, env[i]);
    }
    return 0;
}

通过第三方变量 environ 获取

libc 中定义的全局变量 environ 指向环境变量表,environ 没有包含在任何头⽂件中,所以在使⽤时要⽤ extern 声明。

c 复制代码
#include <iostream>
#include <cstdio>
int main(int argc, char *argv[])
{
    extern char **environ;
    for (int i = 0; environ[i]; i++)
    {
        printf("i: %d environ[%d]: %s\n", i, i, environ[i]);
    }
    return 0;
}

通过系统调用获取或设置

常用 getenvputenv 函数来访问特定的环境变量。

getenv
c 复制代码
NAME
       getenv, secure_getenv - get an environment variable
SYNOPSIS
       #include <stdlib.h>
       char *getenv(const char *name);
       char *secure_getenv(const char *name);
RETURN VALUE
       The getenv() function returns a pointer to the value in the environment, or NULL if there is no match.
c 复制代码
#include <iostream>
#include <cstdio>
int main(int argc, char *argv[], char *env[])
{
    printf("PATH: %s\n", getenv("PATH"));
    printf("PWD:%s\n", getenv("PWD"));
    printf("HOME:%s\n", getenv("HOME"));
    return 0;
}
putenv
c 复制代码
NAME
       putenv - change or add an environment variable
SYNOPSIS
       #include <stdlib.h>
       int putenv(char *string);
RETURN VALUE
       The putenv() function returns zero on success.  On failure, it returns a nonzero value, and errno is set to indicate the error.
c 复制代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
int main(int argc, char *argv[], char *env[])
{
    // 设置新的环境变量
    putenv("NEW_ENV=hello");
    // 修改现有的环境变量
    printf("修改前PATH: %s\n", getenv("PATH"));
    putenv("PATH=/usr/local/bin:/usr/bin");
    printf("修改后PATH: %s\n", getenv("PATH"));
    // 验证设置
    char *ch = getenv("NEW_ENV");
    printf("NEW_ENV: %s\n", ch);
   
    return 0;
}
相关推荐
( •̀∀•́ )9201 小时前
Linux 下部署 `social-auto-upload` 遇到的问题及完整解决方案
linux·运维·服务器
代码中介商1 小时前
Libevent实战:高性能网络编程指南
linux·运维·网络
happytree0011 小时前
linux0.11 - setup.s第一阶段(获取系统信息)
linux
怀旧,1 小时前
【Linux网络编程】2. Socket编程 UDP
linux·网络·udp
徒劳爱学仙2 小时前
全志 V821 韦东山 Avaota-F1-B ubuntu开发环境搭建
linux·运维·ubuntu
z200509302 小时前
【linux学习】linux的基本指令
linux·学习
迷枫7122 小时前
Linux 磁盘管理全攻略:从物理硬件到在线扩容
linux
java_logo3 小时前
轻量AI接口网关一键部署|calciumion/new-api Windows/Linux Docker 部署全教程
linux·人工智能·windows·one api·calciumion·ai网关部署·one api 部署
原来是猿3 小时前
Linux - 【理解进程组、会话与作业控制】
linux·运维·服务器