深入了解Linux中的环境变量
在Linux系统中,环境变量(Environment Variables)是用于配置操作系统和应用程序运行环境的一种机制。它们储存在键值对中,可以控制程序的行为、路径查找和系统配置。本文将深入探讨环境变量的基本概念、常见类型、设置和管理方法,以及一些实用的技巧。
一、环境变量的基本概念
环境变量是在操作系统环境中定义的一些变量,用于存储信息,以便在系统中共享和使用。这些变量可以影响程序的行为和操作系统的功能。
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
首先在介绍环境变量前我们先介绍以下 “命令行参数”这一概念。
我们平常在Linux中输入命令时通常是这么使用的 ls -l copy test.c /home/user
为什么后面可以跟后缀使用呢,这其实就跟我们的命令行参数有关
在C和C++编程中,命令行参数通过main
函数的参数传递给程序。标准的main
函数签名如下:
int main(int argc, char *argv[])
这个签名表明程序可以接受命令行参数,并通过argc
和argv
这两个参数来访问这些输入。接下来,我们详细讲解这两个参数的作用和使用方法。
一、argc
和 argv
的含义
argc
(argument count):表示命令行参数的数量,包括程序名本身。argv
(argument vector):是一个指向字符数组的指针数组,每个元素指向一个命令行参数的字符串。
二、argc
和 argv
的详细说明
1. argc
的作用
argc
是一个整数,表示命令行参数的数量。例如,如果我们运行一个名为my_program
的程序,并传递两个参数:
./my_program arg1 arg2
此时,argc
的值为3,因为包括程序名在内总共有三个参数
2. argv
的作用
argv
是一个指向字符串数组的指针数组。每个元素是一个char*
,指向一个命令行参数。假设上面的程序命令行如下
./my_program arg1 arg2
那么,argv
的内容如下:
argv[0]
:指向字符串"./my_program"
(程序名)。argv[1]
:指向字符串"arg1"
(第一个参数)。argv[2]
:指向字符串"arg2"
(第二个参数)。
argv[argc]
是一个空指针(NULL
),用于标记数组的结束。
三、实例讲解
下面是一个简单的C程序,它演示了如何使用argc
和argv
来处理命令行参数:
#include <stdio.h>int main(int argc, char *argv[]) {// 打印命令行参数的数量printf("Number of arguments: %d\n", argc);// 遍历并打印每一个参数for (int i = 0; i < argc; i++) {printf("Argument %d: %s\n", i, argv[i]);}return 0;
}
假设我们编译并运行该程序,传递一些命令行参数
./my_program arg1 arg2 arg3
输出将是:
Number of arguments: 4
Argument 0: ./my_program
Argument 1: arg1
Argument 2: arg2
Argument 3: arg3
./my_program arg1 arg2 arg3
所以以上命令本质就是 程序的路径 + 名称 后面跟 和该进程匹配的选项
默认是交给父进程bash处理的! 命令中启动的程序都会变成进程,其实都是bash的子进程
那么为什么要有命令行参数呢?
本质:命令行参数本质是交给我们程序的不同选项,用来定制不同的程序功能
下面是一个简单的例子
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 打印帮助信息
void print_help(const char *program_name) {printf("Usage: %s <command> [options]\n", program_name);printf("Commands:\n");printf(" help Show this help message\n");printf(" add <num1> <num2> Calculate the sum of num1 and num2\n");printf(" sub <num1> <num2> Calculate the difference of num1 and num2\n");printf(" mul <num1> <num2> Calculate the product of num1 and num2\n");printf(" div <num1> <num2> Calculate the quotient of num1 and num2\n");
}// 计算两个数的和
void calculate_sum(int num1, int num2) {printf("Sum: %d\n", num1 + num2);
}// 计算两个数的差
void calculate_difference(int num1, int num2) {printf("Difference: %d\n", num1 - num2);
}// 计算两个数的积
void calculate_product(int num1, int num2) {printf("Product: %d\n", num1 * num2);
}// 计算两个数的商
void calculate_quotient(int num1, int num2) {if (num2 == 0) {printf("Error: Division by zero is not allowed.\n");return;}printf("Quotient: %d\n", num1 / num2);
}int main(int argc, char *argv[]) {if (argc < 2) {fprintf(stderr, "Error: No command provided.\n");print_help(argv[0]);return 1;}if (strcmp(argv[1], "help") == 0) {print_help(argv[0]);} else if (strcmp(argv[1], "add") == 0 && argc == 4) {int num1 = atoi(argv[2]);int num2 = atoi(argv[3]);calculate_sum(num1, num2);} else if (strcmp(argv[1], "sub") == 0 && argc == 4) {int num1 = atoi(argv[2]);int num2 = atoi(argv[3]);calculate_difference(num1, num2);} else if (strcmp(argv[1], "mul") == 0 && argc == 4) {int num1 = atoi(argv[2]);int num2 = atoi(argv[3]);calculate_product(num1, num2);} else if (strcmp(argv[1], "div") == 0 && argc == 4) {int num1 = atoi(argv[2]);int num2 = atoi(argv[3]);calculate_quotient(num1, num2);} else {fprintf(stderr, "Error: Invalid command or arguments.\n");print_help(argv[0]);return 1;}return 0;
}
编译并运行上述程序后,可以通过传递不同的命令行参数来执行不同的功能。例如:
./my_program sub 10 5
那为什么内建命令不需要./呢,所以接下来我们继续讲解环境变量
常见的环境变量包括:
- PATH:存储可执行文件的目录路径列表,当你在终端输入命令时,系统会在这些目录中搜索可执行文件。
- HOME:当前用户的主目录路径。
- USER:当前登录的用户名。
- SHELL:用户默认的Shell解释器。
- LANG:系统的语言和区域设置。
二、查看环境变量
可以使用printenv
或env和echo
命令来查看当前的环境变量:
echo + $PATH/HOME
Linux中存在一些全局的设置,告诉命令行解释器应该去哪些路径下去寻找可执行程序
而系统中的很多配置,在我们刚刚登录到Linux中,就已经被加载到了bash进程(内存)中了,
所以我们默认查到的环境变量是内存级别的也就是说不会改变磁盘中的环境变量,当我们再次登录这个环境变量还是会重置!
所以最开始的环境变量不在内存中,而在对应的配置文件中
例如
- .bash_profile
- .bashrc
- /etc/bashrc
- 1. echo: 显示某个环境变量值
- 2. export: 设置一个新的环境变量
- 3. env: 显示所有环境变量
- 4. unset: 清除环境变量
- 5. set: 显示本地定义的shell变量和环境变量
当执行当前目录下的外部命令时,需要使用 ./
进行路径指定。这是因为:
- 安全性考虑:为了避免安全隐患,默认情况下,当前目录
.
并不包含在PATH
环境变量中。这防止了恶意可执行文件以常用命令名命名并被误执行。 - 明确路径:通过使用
./
明确指定当前目录,用户告诉 Shell 要在当前目录中查找并执行相应的可执行文件。
例如,当前目录下有一个名为 my_script.sh
的脚本:
./my_script.sh
如果没有 ./
,Shell 会按照 PATH
中指定的目录查找 my_script.sh
,而不是当前目录。
所以我们把这个可执行程序的路径加入到环境变量中以后就不需要带有路径了。
三、环境变量的组织方式
环境变量在 Bash 内部是以一个键值对(key-value pair)的形式存储的。这些键值对存储在一个全局变量中,该变量在 Bash 的整个生命周期内都可以访问。
环境变量的存储实际上依赖于操作系统提供的环境表。每个进程都有一个环境表,这个环境表是一个字符串数组,其中每个字符串的形式为 KEY=VALUE
。在 Bash 中,使用外部命令 printenv
或内建命令 export
可以查看和管理这些变量。
也就是说bash进程启动的时候会默认给子进程形成两张表,一个是argv[]命令行参数表,另一个是environ[]环境变量表。bash通过各种方式传递给子进程
四、通过代码如何获取环境变量
命令行第三个参数
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{int i = 0;for(; env[i]; i++){printf("%s\n", env[i]);}return 0;
}
通过第三方变量来获取
#include <stdio.h>
int main(int argc, char *argv[])
{extern char **environ;int i = 0;for(; environ[i]; i++){printf("%s\n", environ[i]);}return 0;
}
五、内建命令
内建命令(built-in commands)是由 Shell 自身实现和提供的一类命令。与外部命令(external commands)不同,内建命令不依赖于文件系统中的独立可执行文件,而是直接在 Shell 进程中执行。内建命令的设计和实现旨在提高效率、提供更紧密的 Shell 集成以及实现一些只有 Shell 可以处理的特殊功能。下面详细介绍内建命令的作用与用途。
一、内建命令的主要作用
1. 提高执行效率
由于内建命令直接由 Shell 处理,不需要创建新的进程,因此执行速度比外部命令更快。每次执行内建命令时,Shell 不需要通过文件系统查找命令或创建子进程,这减少了开销和延迟。
2. 提供关键的 Shell 功能
内建命令实现了许多核心的 Shell 功能和控制结构,例如:
- 环境管理:
export
、set
、unset
等命令用于设置和管理环境变量。 - 目录操作:
cd
用于改变当前工作目录。 - Shell 控制:
exit
退出 Shell 会话,exec
替换当前 Shell 进程。 - 条件和循环:
if
、for
、while
等控制结构实现了脚本中的条件和循环逻辑。
3. 处理 Shell 内部状态
一些内建命令可以直接操作和修改 Shell 的内部状态,例如设置选项、启用或禁用特性等:
- 选项设置:
set
命令可以打开或关闭 Shell 的各种选项,例如调试模式、命令别名等。 - 历史记录管理:
history
命令用于查看和操作命令历史记录。
4. 实现复杂的命令组合和脚本
内建命令在脚本编写中起着至关重要的作用。它们提供了丰富的编程构造,使得复杂的命令组合和脚本实现成为可能:
- 函数定义:
function
用于定义 Shell 函数。 - 输入输出重定向:
read
命令用于从标准输入读取数据。
二、内建命令的实现原理
内建命令是 Shell 内部实现的一部分,通常用 C 语言编写,直接集成在 Shell 的源代码中。当用户输入一个命令时,Shell 按照以下顺序进行处理:
- 检查内建命令:首先检查输入的命令是否为内建命令。如果是,则直接在当前进程中执行该命令。
- 检查别名:如果不是内建命令,Shell 接下来检查是否有定义的别名。
- 检查函数:然后,Shell 检查是否有定义的 Shell 函数。
- 搜索外部命令:最后,如果上述都不是,Shell 在
PATH
环境变量指定的目录中搜索外部命令。
这种查找顺序确保了内建命令的高效执行和优先处理。
四、总结
内建命令在 Shell 中发挥着重要作用。它们提高了命令执行的效率,提供了许多关键功能和控制结构,并且能够直接操作 Shell 的内部状态。了解和熟练使用内建命令,可以显著提升使用 Shell 和编写脚本的效率和灵活性。
如果你有任何进一步的问题或需要详细解释的内容,欢迎在评论区留言讨论。
相关文章:

深入了解Linux中的环境变量
在Linux系统中,环境变量(Environment Variables)是用于配置操作系统和应用程序运行环境的一种机制。它们储存在键值对中,可以控制程序的行为、路径查找和系统配置。本文将深入探讨环境变量的基本概念、常见类型、设置和管理方法&a…...

雷军-2022.8小米创业思考-8-和用户交朋友,非粉丝经济;性价比是最大的诚意;新媒体,直播离用户更近;用真诚打动朋友,脸皮厚点!
第八章 和用户交朋友 2005年,为了进一步推动金山的互联网转型,让金山的同事更好地理解互联网的精髓,我推动了一场向谷歌学习的运动,其中一个小要求就是要能背诵“谷歌十诫”。 十诫的第一条就令人印象深刻:以用户为中…...

【Vue2.x】props技术详解
1.什么是prop? 定义:组件标签上注册的一些自定义属性作用:向子组件传递数据特点 可以传递任意数量的prop可以传递任意类型的prop 2.prop校验 为了避免乱传数据,需要进行校验 完整写法 将之前props数组的写法,改为对象…...

C语言例题46、根据公式π/4=1-1/3+1/5-1/7+1/9-1/11+…,计算π的近似值,当最后一项的绝对值小于0.000001为止
#include <stdio.h> #include <math.h>int main() {int fm 1;//分母double sign 1;//正负号double fzs 1;//分子式double sum 0;while (fabs(fzs) > 0.000001) {sum fzs;sign * -1; //变换正负号fm 2; //分母3、5、7、9...增长fzs sign / fm;//分子式…...

fpga系列 HDL: 05 阻塞赋值(=)与非阻塞赋值(<=)
在Verilog硬件描述语言(HDL)中,信号的赋值方式主要分为两种:连续赋值和过程赋值。每种赋值方式有其独特的用途和语法,并适用于不同类型的电路描述。 1. 连续赋值(Continuous Assignment,assign 和…...

大白话DC3算法
DC3算法是什么 DC3算法(也称为Skew算法)是一种高效的构建后缀数组的算法,全称为Difference Cover Modulo 3算法。 该算法于2002年被提出,论文参考: https://www.cs.cmu.edu/~guyb/paralg/papers/KarkkainenSanders0…...

力扣HOT100 - 75. 颜色分类
解题思路: 单指针,对数组进行两次遍历。 class Solution {public void sortColors(int[] nums) {int p 0;int n nums.length;for (int i 0; i < n; i) {if (nums[i] 0) {int tmp nums[i];nums[i] nums[p];nums[p] tmp;p;}}for (int i p; i …...

Vue.js - 计算属性与侦听器 【0基础向 Vue 基础学习】
文章目录 计算属性 computedcomputed 的使用方法computed 与 method 的区别计算属性完整写法 watch 侦听器(监视器)简单写法 → 简单类型数据,直接监视完整写法 → 添加额外配置项 计算属性 computed computed 的使用方法 **概念࿱…...
技术速递|使用 C# 集合表达式重构代码
作者:David Pine 排版:Alan Wang 本文是系列文章的第二篇,该系列文章涵盖了探索 C# 12功能的各种重构场景。在这篇文章中,我们将了解如何使用集合表达式重构代码,我们将学习集合初始化器、各种表达式用法、支持的集合目…...

我的世界开服保姆级教程
前言 Minecraft开服教程 如果你要和朋友联机时,可以选择的方法有这样几种: 局域网联机:优点:简单方便,在MC客户端里自带。缺点:必须在同一局域网内。 有些工具会带有联机功能:优点:一…...

[转载]同一台电脑同时使用GitHub和GitLab
原文地址:https://developer.aliyun.com/article/893801 简介: 工作中我们有时可能会在同一台电脑上使用多个git账号,例如:公司的gitLab账号,个人的gitHub账号。怎样才能在使用gitlab与github时,切换成对应…...
【网络协议】【OSI】一次HTTP请求OSI工作过程详细解析
目录 1. 一次HTTP请求OSI工作过程 1.1 应用层(第7层) 1.2 表示层(第6层) 1.3 会话层(第5层) 1.4 传输层(第4层)...

springboot vue 开源 会员收银系统 (2) 搭建基础框架
前言 完整版演示 前面我们对会员系统https://blog.csdn.net/qq_35238367/article/details/126174288进行了分析 确定了技术选型 和基本的模块 下面我们将从 springboot脚手架开发一套收银系统 使用脚手架的好处 不用编写基础的rabc权限系统将工作量回归业务本身生成代码 便于…...

Java进阶学习笔记26——包装类
包装类: 包装类就是把基本类型的数据包装成对象。 看下API文档: deprecated:极力反对、不赞成的意思。 marked for removal:标识为去除的意思。 自动装箱:基本数据类型可以自动转换成包装类。 自动拆箱:…...

【JavaEE进阶】——要想代码不写死,必须得有spring配置(properties和yml配置文件)
目录 本章目标: 🚩配置文件 🚩SpringBoot配置文件 🎈配置⽂件的格式 🎈 properties 配置⽂件说明 📝properties语法格式 📝读取配置文件 📝properties 缺点分析 dz…...

第十四 Elasticsearch介绍和安装
docker-compose安装 kibana: image: docker.elastic.co/kibana/kibana:7.5.1 container_name: kibana ports: - "5601:5601" environment: ELASTICSEARCH_HOSTS: http://elasticsearch:9200 depends_on: - elasticsearch…...

YOLOv10介绍与推理--图片和视频演示(附源码)
导 读 本文主要对YOLOv10做简单介绍并给出推理图片和视频的步骤演示。 YOLOv10简介 YOLOv10是清华大学的研究人员在Ultralytics Python包的基础上,引入了一种新的实时目标检测方法,解决了YOLO 以前版本在后处理和模型架构方面的不足。通过消除非最大抑…...
Java实验08
实验一 demo.java package q8.demo02;public class demo{public static void main(String[] args) {WindowMenu win new WindowMenu("Hello World",20,30,600,290);} }WindowMenu.java package q8.demo02; import javax.swing.*;public class WindowMenu extends…...

MyBatis复习笔记
3.Mybatis复习 3.1 xml配置 properties:加载配置文件 settings:设置驼峰映射 <settings><setting name"mapUnderscoreToCamelCase" value"true"/> </settings>typeAliases:类型别名设置 #这样在映射…...
HTML的基石:区块标签与小语义标签的深度解析
📚 HTML的基石:区块标签与小语义标签的深度解析 🌐 区块标签:构建网页的框架🏠 <div>:万能的容器📚 <section>、<article>、<aside>:语义化的布局 …...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...