【Linux】命令行参数 | 环境变量(四)

news2025/4/21 10:00:01

目录

前言:

一、命令行参数:

1.main函数参数

2.为什么有它?

二、环境变量:

1.main函数第三个参数

2.查看shell本身环境变量

3.PATH环境变量

4.修改PATH环境变量配置文件 

5.HOME环境变量

6.SHELL环境变量

7.PWD环境变量

8.USER和LOGNAME环境变量

9.OLDPWD环境变量

三、理解环境变量:

1.本地变量(临时变量)

2.set查看所有变量

3.export导入环境变量

4.unset取消环境变量

5.环境变量的全局属性 

6.环境变量表

四、命令总结:

总结:


前言:

我们已经了解了进程的很多概念,上次讲到了进程调度算法,这次我们来一个更炸裂的环境变量,大家应该都学过JAVA,每次都要下载并配置环境变量,这次,我们来彻底搞懂它。

一、命令行参数:

1.main函数参数

我们平时写C语言,main函数有参数吗?其实main函数有参数,但是我们从来不会写,这次我们把环境变量参数都打印出来并看看都是什么:

#include<stdio.h>

int main(int argc, char *argv[])
{
    printf("argc: %d\n", argc);

    for (int i = 0; i < argc; ++i) 
    {
        printf("argv[%d]: %s\n", i, argv[i]);
    }
    return 0;
}

等等,这里你可能无法直接编译生成可执行程序:

 

我们平时使用的VS后面其实默认添加了,所以我们再makefile中指定标准:

此时再次make就不会报错。

我们在命令行中多传入几个参数并观察结果: 

当然也可以是其他字符:

所以,我们把main函数参数中的argv叫做命令行参数列表;argc叫做参数的个数。

2.为什么有它?

比如现在写一个只要两个参数的程序:

#include<stdio.h>
#include<string.h>

// code -opt1/-opt2/-opt3
int main(int argc, char *argv[])
{
    if (argc != 2) 
    {
        printf("Usage: code -opt\n");
        return 1;
    }

    if (strcmp(argv[1], "-opt1") == 0)
    {
        printf("功能1\n");
    }
    else if (strcmp(argv[1], "-opt2") == 0)
    {
        printf("功能2\n");
    }
    else if (strcmp(argv[1], "-opt3") == 0)
    {
        printf("功能3\n");
    }
    else 
    {
        printf("默认功能\n");
    }
    return 0;
}

我们来测试一下:

有没有似曾相识?我们平时使用的命令都会加上选项,而这些命令都是C语言实现的。可以让同一个程序,根据命令行参数的选项,表现出不同的功能。比如:指令中选项的实现。

在命令行中,我们平时输入的命令其实是一串字符串,首先会被shell(bash命令行)拿到,之后按照空格打散,形成一张表(argv)和元素个数(argc)

命令行启动的程序,父进程都是shell。对于数据(尤其是只读的),子进程也能看到。 

main函数也是被调用的,父进程都是shell,一般传入下面三个参数:

二、环境变量:

1.main函数第三个参数

我们刚才看到main函数的参数有三个,main函数第三个参数env,我们这次打印出所有的环境变量:

以key-value方式构建的,具有“全局”属性的变量,叫做全局属性。

常见的环境变量:

PATH: 指定命令的搜索路径

HOME: 指定用户的主工作目录(即用户登录到Linux系统中时,默认的目录)

SHELL: 当前Shell,它的值通常是/bin/bash

2.查看shell本身环境变量

在命令行想看shell本身自己的环境变量,输入env即可:

和之前打印出来的一样。

这次我们修改代码:

3.PATH环境变量

为什么系统知道命令在usr/bin目录下?我们可以让他认识我们的路径吗?

PATH环境变量,告诉了shell,执行命令时,应该去哪个路径下查。如果我们想指定看一个环境变量,可以使用如下命令:

这代表当shell运行任何一个命令时,首先要查PATH中的路径,之后看里面有没有对应的命令。

PATH是一个路径集合,是系统可执行文件的搜索路径的集合

所以,我们可以修改PATH,把自己的路径添加到PATH中,就可以直接执行自己的命令了。

至于为什么有的命令还能跑,我们以后再解释。但是现在有一个问题,我们把之前的路径都覆盖了,怎么恢复?其实在环境变量加载的时候,我们就已经把其加载到了bash进程内部,是内存级的,保存在进程的上下文中。也就是相当于我们malloc出来一块空间,此时把malloc空间中的内容修改了,所以我们重启一下Xshell即可。

所以在修改PATH时,不要直接把PATH修改为我们想修改的路径,要把之前的路径加上去,再添加我们的路径:

所以环境变量PATH本质就是内存级的变量通过shell维护,可以通过一定方式修改PATH变量。所以这次我们关掉Xshell依旧还是原来的PATH路径,不会添加你之前添加的内容。

4.修改PATH环境变量配置文件 

但是,这些内容一开始是从哪里的来的?最开始PATH环境变量一定不再内存中,而是在系统的配置文件中。

当我登陆的时候,会启动一个shell进程,此时就会读取用户和系统相关的环境变量的配置文件形成自己的环境变量表。

所以我们修改配置文件,我们一旦登录Linux一定是一个具体的用户在登陆,登录后一定处在自己的家目录下,所以系统中家目录下会存在两个配置文件(.bash_profile, .bashrc)。当bash启动时,就会读取这两个环境变量,形成自己的环境变量信息。

所以我们将之前code所在文件路径添加到.bash_profile文件中,并观察效果:

如果没有成功(因为刚才已经添加过了临时新的环境变量,所以这里没有执行该命令),让一个更改后的配置文件生效可以使用该命令:

source .bash_profile

我们之前讲解过uid,也就是进程内部会记录是谁启动的这个进程。但是你启动进程的时候,系统怎么会知道你是谁?并且把你的uid写入到pcb中呢?因为:

5.HOME环境变量

因为命令行执行的命令都是bash的子进程,所以当我们切换路径的时候,也就把bash的cwd的属性给改了。 所以创建的所有进程路径都源自于bash的cwd路径:

当我们切换路径,就会改变bash的cwd:

所以为什么最开始我们处于家目录中?因为最开始读取配置文件中的环境变量(HOME),然后bash把自己的cwd设置在了HOME变量中。 

所以系统读取配置文件时,首先一定知道登录的用户是谁,一旦发现不是root,之后就会更改为/home/XXX把环境变量设置好,之后chdir更改cwd即可。把bash的cwd改为当前工作路径(家目录下)。

6.SHELL环境变量

还有一个环境变量是SHELL,它会记录系统启动时,使用的哪个shell(当前就是bash):

7.PWD环境变量

还有一个环境变量是PWD,是保存当前路径的:

为什么要这么做?

我们可以通过代码获取环境变量,如果按照之前的方法,是获取所有环境变量之后匹配,这样并不优雅,系统提供了对应的函数getenv:

getenv函数获取环境变量的内容,返回char*。获取成功返回值,失败返回NULL。

  • PWD是一个具体的命令,用于显示当前目录路径。

  • CWD 是一个概念,表示程序或进程当前的工作目录。

 PWD的输出取决于进程的 CWD,而 CWD 是进程可以动态修改的。

8.USER和LOGNAME环境变量

我们直接打印出环境变量观察这两者的内容:

当前两者是一致的。此时执行su -:

我们再先以gan身份登录,之后登录到跟用户:

所以当我们登陆的时候,LOGNAME和USER是一致的;su -执行后本质是以root身份登录的;而su root不会改变原来的LOGNAME和USER,只是改变了执行身份。

所以我们区分使用系统的用户以环境变量USER区分。

我们可以修改envtest.c代码来观察现象:

之后先以gan用户执行,之后su -再次执行该代码:

也就是说我们可以通过代码来进行身份认证,我们这里可以演示一下:
 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
    //可以让我的程序识别用户身份,只让gan用户访问
    const char* who = getenv("USER");
    if (strcmp(who, "gan") == 0) {
        printf("执行程序正常命令\n");
        return 0;
    } 
    else
    {
        printf("无权访问!\n");
        return 1;
    }
    return 0;
}

这样就可以写一些可以对用户权限进行控制的程序。 

9.OLDPWD环境变量

我们先记录当前路径:

之后cd ~回家,查看env。发现有一个OLDPWD环境变量记录我们上次所在路径:

再次cd -:

所以PWD记录当前工作路径,OLDPWD记录你上次所在工作路径。所以cd -就是基于这个环境变量实现的。 

以上为认识环境变量。

三、理解环境变量:

系统提供的具有"全局"属性的变量。

1.本地变量(临时变量)

shell也支持我们直接在本地定义变量:

这样定义的变量不属于环境变量,我们使用env并查不到。

在命令行输入的"a=10"这样的语句其实是一段字符串,被shell先读到,shell(一个进程)也就会把这个字符串维护起来,就相当于malloc一块空间。这种变量叫做本地变量不会被环境变量查到。

2.set查看所有变量

如果现在想查到环境变量和本地变量都查到,可以使用set来查询:

本地变量一般给自己用。 

3.export导入环境变量

我们也可以把本地变量导出到环境变量:

以下这个图方便各位更好地理解环境变量,本地变量和argv表: 

当我们export i之后,会导入环境变量。

bash重启以后,export的变量也会消失

当然也可以直接使用export b=100直接导入环境变量。

所以bash不仅认识变量,还认识while循环等语句,所以衍生出了一门shell脚本语言。

设计一个只执行一次的程序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

int main()
{
    char* isrunning = getenv("ISRUNNING");
    if (isrunning == NULL)
    {
        while(1)
        {
            printf("当前进程首次启动!\n");
            sleep(1);
        }
    } 
    else 
    {
        printf("当前进程已经运行了!\n");
    }
    return 0;
}

环境变量是可以被子进程继承的。

4.unset取消环境变量

我们使用unset取消导入的环境变量(unset不仅可以取消你自己定义的环境变量,还可以取消大多数非只读的环境变量和 shell 变量,包括一些由系统或 shell 自动设置的环境变量。不过,只读变量(如PWD等)无法被取消): 

5.环境变量的全局属性 

环境变量可以被所有bash之后的进程全部看到,所以环境变量具有"全局属性"。系统的配置信息,尤其是具有"指导性"的配置信息,它是系统配置起效的一种表现。

进程具有独立性,环境变量可以用来进程间传递数据(只读数据)。

6.环境变量表

其实还有第三种获取环境变量的方法:

使用environ获取环境变量, environ是一个包含在unistd.h中的全局变量,是一个二级指针,它指向环境变量的表:

我们可以用代码来使用一下它:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>

extern char** environ;

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

四、命令总结:

env :  查看shell本身自己的环境变量。

set : 查看所有变量,包括临时变量。

unset : 取消非只读环境变量。

export : 导入环境变量

总结:

我们目前已经认识了很多的环境变量,但是其实使用的还是很少,而且它到底有什么用?我们会在下一节进程地址空间来更加具体的理解。加油吧,各位!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2308594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java高级(IO流多线程)

file 递归 字符集 编码 乱码gbk&#xff0c;a我m&#xff0c;utf-8 缓冲流 冒泡排序 //冒泡排序 public static void bubbleSort(int[] arr) {int n arr.length;for (int i 0; i < n - 1; i) { // 外层循环控制排序轮数for (int j 0; j < n -i - 1; j) { // 内层循环…

深度剖析数据分析职业成长阶梯

一、数据分析岗位剖析 目前&#xff0c;数据分析领域主要有以下几类岗位&#xff1a;业务数据分析师、商业数据分析师、数据运营、数据产品经理、数据工程师、数据科学家等&#xff0c;按照工作侧重点不同&#xff0c;本文将上述岗位分为偏业务和偏技术两大类&#xff0c;并对…

Web3.py 入门笔记

Web3.py 学习笔记 &#x1f4da; 1. Web3.py 简介 &#x1f31f; Web3.py 是一个 Python 库&#xff0c;用于与以太坊区块链进行交互。它就像是连接 Python 程序和以太坊网络的桥梁。 官方文档 1.1 主要功能 查询区块链数据&#xff08;余额、交易等&#xff09;发送交易与…

NFC拉起微信小程序申请URL scheme 汇总

NFC拉起微信小程序&#xff0c;需要在微信小程序开发里边申请 URL scheme &#xff0c;审核通过后才可以使用NFC标签碰一碰拉起微信小程序 有不少人被难住了&#xff0c;从微信小程序开发社区汇总了以下信息&#xff0c;供大家参考 第一&#xff0c;NFC标签打开小程序 https://…

《Python实战进阶》No 8:部署 Flask/Django 应用到云平台(以Aliyun为例)

第8集&#xff1a;部署 Flask/Django 应用到云平台&#xff08;以Aliyun为例&#xff09; 2025年3月1日更新 增加了 Ubuntu服务器安装Python详细教程链接。 引言 在现代 Web 开发中&#xff0c;开发一个功能强大的应用只是第一步。为了让用户能够访问你的应用&#xff0c;你需…

【JAVA SE基础】抽象类和接口

目录 一、前言 二、抽象类 2.1 抽象类的概念 2.2 抽象类语法 2.3 抽象类特性 2.4 抽象类的作用 三、接口 3.1 什么是接口 3.2 语法规则 3.3 接口使用 3.4 接口特性 3.5 实现多接口 3.6 接口间的继承 四、Object类 4.1 获取对象信息&#xff08; toString() &…

530 Login fail. A secure connection is requiered(such as ssl)-java发送QQ邮箱(简单配置)

由于cs的csdN许多文章关于这方面的都是vip文章&#xff0c;而本文是免费的&#xff0c;希望广大网友觉得有帮助的可以多点赞和关注&#xff01; QQ邮箱授权码到这里去开启 授权码是16位的字母&#xff0c;填入下面的mail.setting里面的pass里面 # 邮件服务器的SMTP地址 host…

计算机毕业设计SpringBoot+Vue.js体育馆使用预约平台(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

MyBatis-Plus 为简化开发而生【核心功能】

文章目录 一、前言二、快速入门1. 入门案例2. 常见注解3. 常见配置 三、核心功能1. 条件构造器2. 自定义 SQL3. Service 接口3.1 基本使用3.2 复杂条件 一、前言 顾名思义&#xff0c;MyBatis-Plus 其实是 MyBatis 的一个加强版&#xff0c;它可以帮助我们快速高效地编写数据库…

【MySQL】(2) 库的操作

SQL 关键字&#xff0c;大小写不敏感。 一、查询数据库 show databases; 注意加分号&#xff0c;才算一句结束。 二、创建数据库 {} 表示必选项&#xff0c;[] 表示可选项&#xff0c;| 表示任选其一。 示例&#xff1a;建议加上 if not exists 选项。 三、字符集编码和排序…

通信原理速成笔记(信息论及编码)

信息论基础 信息的定义与度量 信息是用来消除不确定性的内容。例如&#xff0c;在猜硬币正反的情境中&#xff0c;结果存在正反两种不确定性&#xff0c;而得知正确结果能消除这种不确定性&#xff0c;此结果即为信息。单个事件的信息量&#xff1a;对于离散信源中的事件xi​&…

云和恩墨亮相PolarDB开发者大会,与阿里云深化数据库服务合作

2025年2月26日&#xff0c;备受瞩目的阿里云PolarDB开发者大会于北京嘉瑞文化中心盛大举行&#xff0c;众多行业精英齐聚一堂&#xff0c;共襄技术盛会。云和恩墨作为阿里云重要的生态合作伙伴受邀参会。云和恩墨联合创始人兼技术研究院总经理杨廷琨与阿里云智能数据库产品事业…

Linux下的网络通信编程

在不同主机之间&#xff0c;进行进程间的通信。 1解决主机之间硬件的互通 2.解决主机之间软件的互通. 3.IP地址&#xff1a;来区分不同的主机&#xff08;软件地址&#xff09; 4.MAC地址&#xff1a;硬件地址 5.端口号&#xff1a;区分同一主机上的不同应用进程 网络协议…

AI数据分析:用DeepSeek做数据清洗

在当今数据驱动的时代&#xff0c;数据分析已成为企业和个人决策的重要工具。随着人工智能技术的快速发展&#xff0c;AI 驱动的数据分析工具正在改变我们处理和分析数据的方式。本文将着重介绍如何使用 DeepSeek 进行数据清洗。 数据清洗是数据分析的基础&#xff0c;其目的是…

把GB型材库放入solidwork中点击库无法应

1、文件夹的位置要选择对&#xff0c;如下图&#xff1a; 2、文件夹一定要嵌套三层&#xff0c;如下图

IP-----动态路由OSPF(2)

这只是IP的其中一块内容&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为动态路由OSPF &#xff0c;可通过以下路径查看IP-----动态路由OSPF-CSDN博客,欢迎指正 注意&#xff01;&#xff01;&#xff01;本部分内容较多所以分成了两部分在上一章 5.动态路…

《HelloGitHub》第 107 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

计算机毕业设计Python+DeepSeek-R1大模型游戏推荐系统 Steam游戏推荐系统 游戏可视化 游戏数据分析(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

网络流算法: Dinic算法

图论相关帖子 基本概念图的表示: 邻接矩阵和邻接表图的遍历: 深度优先与广度优先拓扑排序图的最短路径:Dijkstra算法和Bellman-Ford算法最小生成树二分图多源最短路径强连通分量欧拉回路和汉密尔顿回路网络流算法: Edmonds-Karp算法网络流算法: Dinic算法 环境要求 本文所用…

Spring Boot 3.x 基于 Redis 实现邮箱验证码认证

文章目录 依赖配置开启 QQ 邮箱 SMTP 服务配置文件代码实现验证码服务邮件服务接口实现执行流程 依赖配置 <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr…