当前位置: 首页 > news >正文

Linux系统编程Day12 -- 环境变量(初识)

往期内容回顾

        进程状态的优先级和特性

        进程属性和常见进程

        进程管理

        理解计算机的软硬件管理


Linux 环境变量详解

        前言:为什么要学习环境变量

        在 Linux 系统中,环境变量(Environment Variables)是一个非常重要的概念,它们就像系统运行的“配置开关”,决定了程序运行的方式、查找文件的路径、默认语言等。

如果你会正确使用环境变量,不仅可以 高效地配置开发环境,还可以 定制命令行为,甚至在 自动化脚本 中发挥巨大作用。

无论是系统管理员、开发者还是普通 Linux 用户,都应该掌握环境变量的基本概念与用法。


主要学习内容

  1. 环境变量的概念与作用

  2. 查看环境变量的方法

  3. 常见的重要环境变量

  4. 设置环境变量

  5. 永久保存环境变量

  6. 删除环境变量

  7. 环境变量与 Shell 的关系

  8. 环境变量在脚本中的应用


1. 环境变量的概念与作用

环境变量是一组 键值对(key=value)的配置,用来影响 Linux 系统和应用程序的运行环境。

  • 作用

    • 告诉系统或程序应该在哪个目录找可执行文件(PATH)

    • 设置默认语言(LANG)

    • 配置用户主目录(HOME)

    • 控制临时文件位置(TMPDIR)

  • 特点

    • 临时的环境变量只在当前会话有效

    • 可以通过配置文件设置成永久变量

    • 变量名区分大小写,通常是全大写


2. 查看环境变量的方法

  • env:显示所有环境变量

    env

    printenv:查看指定变量

    printenv PATH

    echo:输出变量值

    echo $PATH

3. 常见的重要环境变量

变量名

作用

PATH

可执行文件的搜索路径

HOME

当前用户主目录

USER

当前用户名

SHELL

当前使用的 Shell 类型

LANG

系统语言设置

PWD

当前工作目录

EDITOR

默认文本编辑器

MAIL

邮件存储位置


4. 设置环境变量

临时设置(仅在当前会话有效):

export MYVAR="Hello Linux"
echo $MYVAR

c语言编译后常常我们在某些条件下无法执行程序,出现“permission denied!”,计算机是如何制定我们无法访问的呢?

c语言里提供了 “getenv()”函数用于获取环境变量。下面有一段代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define USER "USER"
int main(){char* who = getenv(USER);if(strcmp(who,"root")!=0){printf("Permissiong denied!\n");}else{printf("Hello root User!\n");}}

通过获取USER的环境变量来获取当前使用用户,如果当前用户不是root用户,就输出“permission denied!”,如果是就可以访问: 


为什么真实系统会出现 “Permission denied”

当你在 Linux 下运行一个程序时,系统会根据文件权限用户身份来判断是否允许执行。

判断逻辑大致是:

  1. 每个文件在磁盘上有一个 所有者 (owner)所属组 (group) 和 其他用户 (others) 的权限字段。

  2. 这三个类别的权限用 rwx 表示(r=读,w=写,x=执行)。

  3. 当你运行程序时,内核会:

    • 获取当前进程的 实际用户ID (UID) 和 有效用户ID (EUID)

    • 获取目标文件的权限位(stat 系统调用)。

    • 根据 UID 和文件的 owner/group 关系判断是否有执行 (x) 权限。

  4. 如果判断结果不允许执行,就返回 EACCES,Shell 就显示:


  • 任何你在 bash 终端里运行的程序,默认就是 bash 的子进程

  • 你可以用 ps 命令确认进程的父进程 ID (PPID) 来验证关系

ps -f

UID          PID    PPID  C STIME TTY          TIME CMD

user     174407  174406  0 17:47 pts/1    00:00:00 -bash

user     175461  174407  0 17:55 pts/1    00:00:00 ps -f


本地变量:

直接在终端输入:

val = 1234;

利用set查看所有shell变量(环境变量和shell变量)

set | grep val

5. 永久保存环境变量

根据作用范围不同,修改不同文件:

  • 当前用户:~/.bashrc 或 ~/.bash_profile

  • 所有用户:/etc/profile 或 /etc/environment

    例如:

echo 'export MYVAR="Hello World"' >> ~/.bashrc
source ~/.bashrc

6. 删除环境变量

  • 使用 unset 命令:

unset MYVAR


7. 环境变量与 Shell 的关系

  • 环境变量本质上是 Shell 的一部分,它们通过 Shell 进程传递给子进程

  • 子进程可以继承父进程的环境变量,但修改不会影响父进程。

  • 不同 Shell(bash、zsh、sh)加载环境变量的配置文件路径可能不同


8. 环境变量在脚本中的应用

在 Shell 脚本中可以直接使用环境变量:

#!/bin/bash
echo "当前用户:$USER"
echo "主目录:$HOME"

运行脚本时,脚本会读取当前 Shell 的环境变量

在c语言,python,c++,matlab等语言中,同样也有着类似于shell的pwd等命令,接下来我们简单实用c语言实现 pwd命令的c接口

#include<stdio.h>
#include<stdlib.h>
#define PWD "PWD"
int main(){printf("%s\n",getenv(PWD));
}

这样我们就实现了一个我们的pwd命令

然后将这段代码的执行文件放入 --> /usr/bin/ 文件路径即可。

[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ sudo cp PWD /usr/bin/
[sudo] password for Yajun: 
[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ PWD
/home/Yajun

同样这样我们也可以实现其他的环境变量。


总结

  • 环境变量是 Linux 系统运行的“全局配置参数”,掌握它能让你灵活地控制系统和程序的行为。

  • 要会 查看(env/printenv/echo)设置(export)删除(unset) 以及 永久保存 环境变量。

  • 在实际工作中,环境变量在 程序部署、脚本编写、开发环境配置 等方面都有重要作用。


二、命令行参数

前言

        当我们在命令行(比如Linux终端、Windows命令提示符)执行一个程序时,除了直接运行程序本身,还可以附加一些参数来影响程序的行为。这些参数被称为命令行参数(Command Line Arguments)

命令行参数让同一个程序能应对多种需求,而不用每次都改代码重新编译。例如:你可以用参数指定输入文件名、控制程序的运行模式、传递配置信息等等。

C语言作为底层的编程语言,自然提供了对命令行参数的支持。这也让C语言编写的程序可以方便地接收外部输入,从而灵活运行。


1、什么是命令行参数?

        在命令行执行程序时,格式通常是:

./myprogram arg1 arg2 arg3 ...

./myprogram 是你要执行的程序

arg1, arg2, arg3 是传递给程序的参数,可以是文件名、数字、字符串等。

这些参数都会被操作系统传递给程序,程序通过特定方式读取和使用它们。


2、C语言中main函数和命令行参数

C语言程序的入口是 main 函数,标准形式允许有两种参数形式:

int main(int argc, char *argv[])

或者

int main(int argc, char **argv)

这两个参数分别代表什么?

  • argc(argument count):整数,代表传给程序的命令行参数个数

    • 包含程序本身的名字,所以至少是1。

    • 例如:./myprogram arg1 arg2,则argc为3。

  • argv(argument vector)字符串数组,保存所有命令行参数的指针

    • argv[0] 通常是程序自身的路径或名称,比如 "./myprogram"。

    • argv[1] 是第一个参数 "arg1",argv[2] 是第二个参数 "arg2",以此类推。

    • argv[argc] 是一个空指针 NULL,表示数组结束。


main函数参数可以有几个?

  • 标准C中,main函数可以写成以下三种形式(常见用法):

int main(void)            // 不接收任何命令行参数
int main(int argc, char *argv[])   // 接收命令行参数
int main(int argc, char **argv)    // 和上面等价

另外,有些平台允许第三个参数 char *envp[] 用来接收环境变量,但这不是标准,且一般不常用

下面是一段c语言代码用于测试命令行参数:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(int argc,char* argv[]){while (argc--) {printf("argc[%d] --> %s\n",argc,*argv);argv++;}   
}

运行后输出:

argc[0] --> ./cmp

如果你在命令行上输入选项:例如 “66”,“ok”

ENV_VAL % ./cmp  "66" "ok"  

输出描述:

argc[2] --> ./cmp
argc[1] --> 66
argc[0] --> o

如何理解命令行参数的传递?

        操作系统在执行程序时,会将命令行参数打包成一个字符串数组,并传递给程序的 main。这让程序能够按顺序读取每个参数,进行相应处理。

程序可以根据参数的不同执行不同逻辑,常见做法是:

  • 检查参数个数是否符合预期

  • 遍历参数数组,解析参数内容

  • 使用参数值影响程序行为,比如打开指定文件、设置调试模式等


命令行参数的实际使用

        

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(int argc,char* argv[]){//while (argc--) {//  printf("argc[%d] --> %s\n",argc,*argv);//argv++;if(argc != 2){ printf("Usage:\n\t%s[-a/-b/-ab/-ac/-bc/-abc]\n",argv[0]);return 1;}   if(strcmp(s1: "-a",s2: argv[1]) == 0){ printf("Function: a\n");}   if(strcmp(s1: "-b",s2: argv[1]) == 0){ printf("Function: b\n");}   if(strcmp(s1: "-ab",s2: argv[1]) == 0){ printf("Function: ab\n");}   if(strcmp(s1: "-ac",s2: argv[1]) == 0){ printf("Function: ac\n");}   if(strcmp(s1: "-bc",s2: argv[1]) == 0){ printf("Function: bc\n");}   if(strcmp(s1: "-abc",s2: argv[1]) == 0){ printf("Function: abc\n");}   
}

假设我只运行程序,无输入选项。输出描述:

Usage:

./cmp[-a/-b/-ab/-ac/-bc/-abc]


假如我终端输入是:

./cmp -a

输出:Function: a

第三个参数 char *envp[] 用来接收环境变量,一般不常用里面存放的是系统传入的环境变量。

环境变量作为命令行参数实现:

实现下面这段c语言代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main(int argc,char* argv[],char* env[]){for(int i = 0;env[i];i++){printf("env[%d] :%s\n",i,env[i]);}
}

输出值:

env[0] :TMPDIR=/var/folders/_4/b9p9kkg11r97_ss_c0zt4njm0000gn/T/

env[1] :__CFBundleIdentifier=com.apple.Terminal

env[2] :XPC_FLAGS=0x0

env[3] :TERM=xterm-256color

env[4] :DISPLAY=/private/tmp/com.apple.launchd.aHLlRX784j/org.xquartz:0

env[5] :SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.bfH0Ve9RH4/Listeners

env[6] :XPC_SERVICE_NAME=0

env[7] :TERM_PROGRAM=Apple_Terminal

env[8] :TERM_PROGRAM_VERSION=455.1

env[9] :TERM_SESSION_ID=6F7C1166-D886-453F-9B32-1A8F19F89529

env[10] :SHELL=/bin/zsh

env[11] :HOME=/Users/junye

env[12] :LOGNAME=junye

env[13] :USER=junye

env[14] :PATH=/Users/junye/anaconda3/bin:/Users/junye/anaconda3/condabin:/opt/homebrew/bin:/opt/homebrew/sbin:/Library/Frameworks/Python.framework/Versions/3.12/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/X11/bin:/Library/Apple/usr/bin

env[15] :SHLVL=1

env[16] :PWD=/Users/junye/Desktop/Linux/ENV_VAL

env[17] :OLDPWD=/Users/junye/Desktop/Linux

env[18] :HOMEBREW_PREFIX=/opt/homebrew

env[19] :HOMEBREW_CELLAR=/opt/homebrew/Cellar

env[20] :HOMEBREW_REPOSITORY=/opt/homebrew

env[21] :INFOPATH=/opt/homebrew/share/info:

env[22] :HOMEBREW_API_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles/api

env[23] :HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles/bottles

env[24] :CONDA_EXE=/Users/junye/anaconda3/bin/conda

env[25] :_CE_M=

env[26] :_CE_CONDA=

env[27] :CONDA_PYTHON_EXE=/Users/junye/anaconda3/bin/python

env[28] :CONDA_SHLVL=1

env[29] :CONDA_PREFIX=/Users/junye/anaconda3

env[30] :CONDA_DEFAULT_ENV=base

env[31] :CONDA_PROMPT_MODIFIER=(base)

env[32] :LC_CTYPE=UTF-8

env[33] :_=/Users/junye/Desktop/Linux/ENV_VAL/./cmp

这就是系统导入的环境变量


第二种方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
extern char** environ;
int main(){for(int i = 0; environ[i]!=NULL;i++){printf("ENV[%d]: %s\n", i,environ[i]);}   
}

这里我们外部导入了 environ 里面存放了许多环境变量,因为环境变量都是字符串,对应的也就是char*,所以envirom是一个二级指针。


第三种方法:getenv获取环境变量


提问:

        

[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ hello=888
[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ env | grep hello
[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ set | grep hello
hello=888
[Yajun@iZwz9b70mwpeltilcusk8bZ ~]$ echo $hello
88

        echo 是 一个命令,最后运行echo的时候会产生进程,但是hello是一个本地变量,理论上无法被子进程继承。那么为什么echo可以打印出本地变量呢?

解释:

1. 你写的 hello=888 到底是什么变量?

  • 在 Shell 里,直接写 hello=888,这是定义了一个 Shell 的本地变量(也叫普通变量),它只在当前 Shell 进程内部有效,不会自动传递给子进程。

  • 因此你用 set | grep hello 能看到它(set 显示所有本地变量和函数),但 env | grep hello 看不到(env 只显示环境变量,即被导出的变量)。

2. 为什么 echo $hello 能打印变量值

  • echo 是一个 Shell 内置命令(builtin),它是在当前 Shell 进程内部运行的,不是新启动的子进程。

  • 因此它能直接访问当前 Shell 的本地变量 hello,所以 echo $hello 输出是 888。

3. 为什么 env | grep hello 没有结果

  • env 命令启动了一个新的子进程,它只会看到已经导出(export)成环境变量的变量。

  • 你的 hello 变量没有用 export hello,所以它不会进入环境变量,子进程 env 看不到。

类型

存储位置

继承给子进程?

说明

本地变量

Shell内部数据结构

只在当前Shell进程有效

环境变量

进程的环境内存块

由操作系统管理,fork时复制给子进程

导出变量(export)

从本地变量转为环境变量

通过export使本地变量变成环境变量

总结一下:

  • 环境变量是操作系统为进程维护的一组键值对,表示进程运行的环境信息,父进程的环境变量会被子进程继承,但子进程修改环境变量不会影响父进程。

  • 通过 getenv() 函数可以在程序中读取环境变量的值;也可以通过全局变量 environ 访问全部环境变量列表。

  • 命令行参数是在启动程序时由操作系统传递给程序的额外输入,C语言通过 main(int argc, char *argv[]) 接收,argc 表示参数个数,argv 是参数字符串数组,其中 argv[0] 是程序名本身。

  • 程序通过命令行参数可以灵活调整行为,而环境变量则提供程序运行时的全局配置环境,两者共同作用,增强程序的可配置性和适应性。

http://www.dtcms.com/a/326367.html

相关文章:

  • [特殊字符][特殊字符][特殊字符]【Maven】pom依赖的版本推荐与依赖冲突问题
  • C#使用EPPlus读写Excel
  • 定制化4G专网架构,满足多行业专属需求
  • 在线代码比对工具
  • HTML5中华美食网站源码
  • 布控球:临时布防场景的高清回传利器-伟博
  • 双椒派™ E2000D 开发板深度解析
  • 【Altium designer】一键添加多个器件参数的“备注”
  • conda一键配置python开发环境
  • echarts 柱状图堆叠踩坑指南 (已解决)
  • 读《精益数据分析》:媒体内容平台全链路梳理
  • 超算中心的机器上怎么部署Linux的?
  • 3.6 修改vuex的状态Mutations ,Actions
  • Tricentis Tosca:现代软件测试的自动化利器
  • Java 包装类简单认识泛型
  • Mysql——单表最多数据量多少需要分表
  • Redis 01 数据结构
  • SSM+Dubbo+Zookeeper框架和springcloud框架,写业务的时候主要区别在哪?
  • 【listlist模拟】
  • 提升行车安全的关键技术:BSD(盲点监测)与DSM(驾驶员监测)是如何工作的?
  • AI(领域)应用落地技术决策指南:从双路径架构到系统性实施
  • Centos 用http ftp搭建本地yum源 保姆级教程
  • 芯片学习 8 :IP集成、cluster、lint
  • 基于MongoDB/HBase的知识共享平台的设计与实现
  • 【09】中兴通讯——中兴 软件工程师 一面,校招,面试问答记录
  • 3DMAX快速散布插件QuickScatter安装使用方法
  • wrap cpp variant as dll for c to use
  • Horse3D引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
  • copyleft的遗传特性
  • Python自动化测试实战:reCAPTCHA V3绕过技术深度解析