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

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

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;
}
相关推荐
肖爱Kun17 小时前
GB28181启动传参的设计
linux·服务器·数据库
剑神一笑17 小时前
Linux systemctl 服务管理命令:从 systemd 架构到实战技巧
linux·服务器·架构
艾莉丝努力练剑17 小时前
【Linux网络】传输层协议TCP(六)补充 - 面试题:HTTP 获取网页的完整过程
linux·运维·网络·tcp/ip·计算机网络·http·udp
norsd17 小时前
CentOS Rocky Linux 设置 ip
linux·tcp/ip·centos
minji...18 小时前
Linux高级IO(六)基于ET模式、单reactor反应堆的epoll版本的TCP计算服务器
linux·服务器·网络·c++·epoll·socket套接字·reactor反应堆模式
jcbut19 小时前
在Linux上安装Kingbase 9
linux·kingbase·人大金仓·电科金仓
小此方20 小时前
Re:Linux系统篇(二十六)进程篇·十一:从底层原理到 exec* 家族:彻底搞懂 Linux 进程程序替换
linux·运维·服务器
赵民勇1 天前
fuse-overlayfs命令详解
linux·容器
sulikey1 天前
个人Linux操作系统学习笔记6 - 操作系统与进程初识
linux·笔记·学习·操作系统·进程
杨云龙UP1 天前
Oracle RAC / ODA 生产环境指定 PDB 启动 SOP
linux·运维·数据库·oracle