【linux】linux进程概念(四)(环境变量)

目录

基本概念

[echo 查看某个环境变量](#echo 查看某个环境变量)

[env 显示所有环境变量](#env 显示所有环境变量)

[/dev/pts/0 字符设备文件](#/dev/pts/0 字符设备文件)

测试PATH

[getenv 通过系统调用获取环境变量](#getenv 通过系统调用获取环境变量)

命令行参数

指令的原型

打印命令行参数表

环境变量为什么具有全局属性

命令分为常规命令和内建命令

模拟内建命令


基本概念

在Linux系统中,环境变量是一种在操作系统层面设置的全局变量,它们对系统中运行的所有程序和进程都是可见的。环境变量通常用于定义系统运行环境的参数,如用户的主目录(HOME)、搜索路径(PATH)、默认使用的Shell(SHELL)等。
常见的系统级环境变量

Linux 系统默认定义了一系列核心环境变量,用于保障系统正常运行,以下是最常用的几个:

变量名 作用说明 示例值

PATH 最核心的环境变量,定义「系统查找可执行程序的路径列表」(路径用 : 分隔) /usr/local/bin:/usr/bin:/bin

HOME 当前登录用户的主目录路径(不同用户的 HOME 不同) root 用户:/root;普通用户:/home/ubuntu

USER 当前登录的用户名 ubuntu、root

SHELL 当前用户使用的 Shell 类型(如 bash、zsh) /bin/bash

LANG 系统的默认语言和字符编码(如 UTF-8) en_US.UTF-8、zh_CN.UTF-8

PWD 当前工作目录的绝对路径(等同于 pwd 命令的输出) /home/ubuntu/project

OLDPWD 上一次所在的工作目录路径(按 cd - 可返回此目录) /home/ubuntu

TERM 当前终端的类型(用于确保终端与程序的兼容性) xterm-256color

echo $ 查看某个环境变量

echo $环境变量名

env 显示所有环境变量

env指令可以显示所有环境变量

/dev/pts/0 字符设备文件

作用:

输入输出转发:接收用户输入的命令,同时将命令执行结果、系统提示等内容回显给用户("显示字符" 是其输出功能的表现之一,但并非唯一作用);

会话关联 :绑定当前用户的 Shell(如bash)、环境变量(如TERM)等配置,确保终端环境的一致性;

多会话隔离 :每个/dev/pts/N对应独立的终端会话(如多个 SSH 连接),实现不同用户 / 连接的输入输出互不干扰。

通过输出重定向,可将一个会话的内容发送到另一个会话的终端设备

测试PATH

PATH 最核心的环境变量,定义「系统查找可执行程序的路径列表」(路径用 : 分隔) /usr/local/bin:/usr/bin:/bin

1.指令的本质都是可执行程序,这些指令是被放在特定路径下的可执行程序,例如创建一个可执行程序mycmd.c并且编译好之后进行执行

2.在 Linux 系统中,执行当前路径下的自定义程序mycmd时,不能直接输入mycmd(系统会仅在PATH环境变量的路径中查找程序),需用./mycmd的形式执行;其中 "./" 的作用是告诉系统:直接从当前工作路径中查找并运行mycmd程序。

3.那为什么系统里面的指令就可以直接运行呢

这是因为PATH环境变量的原因,PATH是linux系统的指令默认搜索路径,当我们使用命令时,系统会自动到PATH路径下去搜索对应的可执行程序,找到了就直接执行,没有的话会直接报错。

4.例如ls这个命令就存在usr/bin的路径下

5.那么如何让我们自己编写的可执行程序也可以直接运行呢,第一种是直接把我们写的可执行程序移到系统指定的搜索路径下,第二种我们可以直接修改系统的PATH路径,我们应该使用$PATH:路径的方式进行添加我们的路径,添加完以后,那只要是在新路径下的可执行文件都可以像系统命令一样直接运行。

getenv 通过系统调用获取环境变量

我们还可以通过系统调用来获取环境变量

命令行参数

命令行参数是程序运行时通过终端 / 命令行传入的额外输入,用于灵活配置程序行为(无需修改代码即可改变程序逻辑)。几乎所有编程语言都支持解析命令行参数,核心思路一致:程序启动时读取命令行传入的字符串序列,再按规则解析使用。

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

}
  1. main 函数是被 Startup/CRTStartup 调用的函数,支持传参:argc表示参数个数,argv是存储参数的指针数组;在 Linux 中,命令行输入的空格分隔字符串,其首字符指针会被传递给argv,通过argv[]可获取这些参数,以此实现不同操作(这也是 Linux 命令选项的原理,比如mycmd -a的参数个数是 2)。
  2. main 函数支持命令行参数的目的,是为指令、命令、软件提供命令行选项的功能支持。

指令的原型

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

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        printf("请输入:%s -[a|b|c]\n", argv[0]);
        return 0;
    }

    if (strcmp(argv[1], "-a") == 0)
    {
        printf("%s[1]->%s  执行功能1:显示系统信息\n", argv[0], argv[1]);
    }
    else if (strcmp(argv[1], "-b") == 0)
    {
        printf("%s[1]->%s  执行功能2:计算 5*8=%d\n", argv[0], argv[1], 5*8);
    }
    else if (strcmp(argv[1], "-c") == 0)
    {
        printf("%s[1]->%s  执行功能3:输出当前模式:高效模式\n", argv[0], argv[1]);
    }
    else
    {
        printf("default输入:未知选项 %s,请输入 -a/-b/-c\n", argv[1]);
    }

    return 0;
}

指令也是这种类似用命令行传参去对不同的功能进行选择

运行结果如下

打印命令行参数表

  1. argv是存储命令行参数的指针数组(也称 "向量表"),数组末尾会自动添加NULL作为结束标志;若有N个参数,数组实际存储N+1个值(前N个为参数,最后 1 个是NULL)。

  2. 利用NULL对应逻辑值 0 的特性,以argv[cnt]作为for循环的判断条件,从cnt=0开始遍历,直到argv[cnt]NULL时结束循环,即可遍历所有命令行参数。

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

int main(int argc,char* argv[])
{
  int cnt=0;
  for(;argv[cnt];cnt++)
  {
    printf("%s[%d]->%s\n",argv[0],cnt,argv[cnt]);
  }

  return 0;
}

运行结果:使用命令行第三个参数获取环境变量,打印环境变量表

main函数还有第三个参数,这个参数同样是指针数组类型,也是向量表,这里即环境变量表,那么我们就可以类似于打印命令行参数表的方式进行打印这里的环境变量表

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

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

  return 0;
}

环境变量为什么具有全局属性

原因:

bash 是所有进程的 "根父进程" :bash 启动时会从系统配置文件(如/etc/profile)读取环境变量;

子进程会继承父进程的环境变量 :我们运行的所有进程(比如lspython)都是 bash 的子进程(或子进程的子进程),会自动继承父进程的环境变量;

环境变量逐层传递:由于进程是 "多叉树" 结构(bash 是根节点),bash 的环境变量会传递到所有子进程中,因此在整个系统的进程范围内都有效,也就具备了 "全局属性"。

那如何来证明呢

首先引入一个概念本地变量

本地变量是在 bash 命令行中直接定义的变量,仅在当前 bash 进程内有效,不会被子进程继承;环境变量则是可被进程继承的变量,二者相互独立,不属于同一类别。

本地变量可通过export将本地变量转换为环境变量,也可通过unset将环境变量还原为本地变量;

可使用set命令查看系统中所有本地变量与环境变量。

这类变量机制是 shell 环境中进程间参数传递的基础:本地变量用于当前进程的临时数据存储,环境变量则支持跨进程的配置信息共享(比如系统路径PATH、用户信息USER等常用环境变量,正是通过这种继承机制实现全局生效)。

可以看到我设置了一个本地变量MY_ENV,直接利用echo是回显不出来的,说明它不在全局变量中,通过利用搜索set里的变量可以看到的确存在着一个变量MY_ENV=10086

我们知道我们运行的程序,也是fork的子进程,继承fork的环境变量,那么使用如下代码通过getenv查找我们定义的本地变量MY_ENV是否也被继承下来了

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

int main(int argc,char* argv[],char* env[])
{
  printf("%s\n",getenv("MY_ENV");
}

可以看到报错了

那我们利用export把本地变量添加到环境变量

可以看到通过echo和环境变量表都能找到MY_ENV

同时程序也能正常获取MY_ENV

所以说当MY_ENV变成环境变量以后,通过创建子进程,子进程继承bash的环境变量,从而也继承了MY_ENV,所以这时候就能通过系统调用得到MY_ENV了,这都证明了环境变量的全局性。

命令分为常规命令和内建命令

内建命令

原本认为 bash 中命令都是通过 fork 创建子进程执行,但本地变量不会被子进程继承,可echo却能读取本地变量,这似乎矛盾。

实际规则:bash 的命令分两类

常规命令:通过 fork 创建子进程执行,子进程不会继承 bash 的本地变量;

内置命令 :由 bash 自身直接执行(不创建子进程),echo属于内置命令,因此能直接访问 bash 的本地变量。

模拟内建命令

系统调用接口chdir,可以将当前调用的进程的工作目录更改至指定路径下


getcwd 是类 Unix 系统(Linux、macOS 等)中用于获取当前工作目录绝对路径的系统函数

所以通过chdir来模拟内建命令cd 来更改文件的工作路径,并通过getcwd查看变化

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

int main(int argc, char* argv[], char* env[]) {
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        printf("初始工作目录:%s\n", cwd);
    } else {
        perror("getcwd 失败");
        return 1;
    }

    if (argc < 2) {
        fprintf(stderr, "请传入目标目录参数\n");
        return 1;
    }
    if (chdir(argv[1]) != 0) {
        perror("chdir 失败");
        return 1;
    }

    if (getcwd(cwd, sizeof(cwd)) != NULL) {
        printf("切换后工作目录:%s\n", cwd);
    } else {
        perror("getcwd 失败");
        return 1;
    }

    return 0;
}
相关推荐
松涛和鸣2 小时前
DAY32 Linux Thread Programming
linux·运维·数据库·算法·list
eggrall2 小时前
《gdb 与 cgdb 深度解析:命令行调试的效率革命》
linux
源代码•宸2 小时前
分布式缓存-GO(简历写法、常见面试题)
服务器·开发语言·经验分享·分布式·后端·缓存·golang
秦jh_2 小时前
【Qt】常用控件(上)
服务器·数据库·qt
晨曦夜月2 小时前
头文件与目标文件的关系
linux·开发语言·c++
Xyz996_2 小时前
Ansible进行Nginx编译安装的详细步骤
运维·ansible
白仑色2 小时前
java中的anyMatch和allMatch方法
java·linux·windows·anymatch·allmatch
云和数据.ChenGuang2 小时前
自动化运维工程师之ansible启动rpcbind和nfs服务
运维·服务器·运维技术·数据库运维工程师·运维教程
yimengsama2 小时前
VMWare虚拟机如何连接U盘
linux·运维·服务器·网络·windows·经验分享·远程工作