Linux之命令行参数与环境变量

 命令行参数&环境变量

命令行参数

main函数也是一个函数,其实也可以携带参数的


int main( int argc, char *argv[ ], char *envp[ ] )
{
    program-statements
}

 那这里是有三个参数的:

第一个参数: argc 是个整型变量,表示命令行参数的个数(含第一个参数)。

第二个参数: argv 是个字符指针的数组,每个元素是一个字符指针,指向一个字符串。这些字符串就是命令行中的每一个参数(字符串)。

第三个参数: envp 是字符指针的数组,数组的每一个原元素是一个指向一个环境变量(字符串)的字符指针。

先来说前两个参数:

  1 #include <stdio.h>
  2 int main(int argc,char* argv[])
  3 {
  4     int i = 0;
  5     for(;i<argc;i++)
  6     {
  7         printf("%d:%s\n",i,argv[i]);                                       
  8     }
  9 
 10     return 0;
 11 }

它直接把我们上一步输入的命令行给打印出来了,说明我们上一步的命令行被main函数给保存到了argv数组中去,那么,我们尝试着在命令行中在写多一些字符串,来证实一下我们的猜想: 

是这样的

 用命令行参数就可以实现一个简单的交互程序:

 1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 
  5 int main(int argc,char* argv[])
  6 {
  7     if(argc != 4)
  8     {
  9         printf("Use error\nUsage: %s op[-add|sub|mul|div] d1 d2\n", argv[0]); //argv[0], 会不会不存在呢??
 10         return 1;
 11     }              
 12     int x = atoi(argv[2]);                        
 13     int y = atoi(argv[3]);          
 14     int result = 0;
 15     // 你的程序一定有4个命令行参数,第一个是程序名
 16     if(strcmp(argv[1], "-add") == 0)       
 17     {
 18         result = x + y;                  
 19         printf("%d+%d=%d\n", x, y, result);
 20     }                  
 21     else if(strcmp(argv[1], "-sub") == 0)  
 22     {
 23         result = x - y;
 24         printf("%d-%d=%d\n", x, y, result);
 25     }                  
 26     else if(strcmp(argv[1], "-mul") == 0)                                                                         
 27     {
 28         result = x * y;                  
 29         printf("%d*%d=%d\n", x, y, result);
 30     }                                                        
 31     else if(strcmp(argv[1], "-div") == 0)    
 32     {
 33         if( 0 == y ) printf("%d/%d=error! div zero\n", x, y);
 34         else printf("%d/%d=%d\n", x, y, x/y);
 35     } 36     else                    
 37     {
 38         printf("Use error, you should use right command line\nUsage: %s op[-add|sub|mul|div] d1 d2\n", argv[0]); /    /argv[0], 会不会不存在呢??
 39     }
 40 
 41     return 0;
 42 }

还可以模拟实现Linux中的bash指令
当模拟实现了计算器后,我们可以发现,其实Linux下的指令如ls,pwd或touch,其实就是调用了不同的可执行程序来完成的! 我们便不难理解我们的命令行选项的概念了。

在Linux中,命令行选项是通过命令行输入的参数,用于修改命令的行为或提供额外的功能。命令行选项通常以短划线(-)或双短划线(--)开头,后面跟着一个字母或单词。这些选项允许用户在执行命令时自定义命令的行为,通过不同的选项组合可以实现各种不同的功能。我们经常使用的指令其实就相当于一个个可执行程序,后面的一些像 -l,-a,-al之类的均为命令行参数,相当于可以执行不同的功能 。

比如touch指令,输入touch和要创建的文件名本质就是在C语言程序中创建一个和输入的文件名一样的文件来间接创建文件

#include<stdio.h>    
int main(int argc,char* argv[])    
{    
    if(argc != 2)//输入的字符串不规范    
    {    
        printf("touch missing file operand\n");    
        return 1;    
    }    
    FILE* fp = fopen(argv[1],"w");                                                                                                                                      
    if(fp!=NULL)    
        fclose(fp);    
    return 0;    
}  

环境变量

我们在使用一些集成开发环境时,需要我们自己配置环境变量用来满足代码编译需求.

 基本概念

环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。

在Linux中运行代码时我们就会发现,同样是可执行程序,我们自己写的代码就需要带 ./ 才能运行,但是系统中的命令,比如whami 、ls等却不用带 ./ 照样可以执行呢?其实,这里的 ./表示了我们的当前目录,带着目录运行一个可执行程序当然是可以的,我们知道,要执行一个可执行,必须找到自己的可执行在哪里,但是,为什么系统的指令就可以不带目录而独自运行呢?所以:系统指令有自己的默认的查找路径!

查看系统的环境变量

我们可以使用命令:

echo $PATH

在查询结果中,每个环境变量之间以 : 分隔开, 从上面的结果中我们可以看到, 一共有6个系统的默认的环境变量, 我们在使用系统命令时, 系统会自动挨着在这些目录下查找是否有对应的可执行文件, 有就执行, 没有就报错。

添加环境变量

知道了这个功能,我们想尝试着将我们自己的可执行文件的目录添加到环境变量中去,这样,我们运行我们的程序就不用加目录了,我们直接来试一下:

使用指令: PATH = $PATH:要添加的路径 

$PATH表示当前的环境变量, $PATH:[路径]表示将路径追加到原来的PATH中, 如果直接 PATH = [路径], 原来的内容会被覆盖, 和给变量赋值是一样的

这里需要注意,默认的环境变量的修改,仅限于当前的这一次登录,如果用户退出再登录,环境变量就会恢复到原来的状态。这个我们在这里先简单的介绍一下原因,具体后面还会提及:

我们知道,命令行启动的进程都是bash(命令行解释器)的子进程,子进程的命令行参数和环境变量,是父进程传递给的 ,我们每次更改子进程的环境变量信息,实际上更改的是bash进程内部的环境变量信息,而每一次的重新登录,我们知道,bash也是一个进程,所以,我们每次登录时,系统就会为我们创建一个新的bash解释器,重新读取环境变量信息保存到自己的数据信息中。

那么,问题又来了,bash又是从哪里读取到环境变量的信息的呢?

其实这个环境变量信息是以配置文件的方式存在的,也就是脚本形式存在的,这个配置文件在对应用户的家目录的一个隐藏文件 .bash_profiles 中,每次用户登录,都会读取该文件中的内容,该文件会为bash进程生成环境变量表信息。

 

 当我们在配置文件中加上自己想要一直存在的环境变量时,此时bash再次启动后,这个环境变量就会被放到环境变量表中!

并且在创建子进程时,这张表会通过main函数的参数传递给子进程,所以子进程有了和父进程一样的环境变量表,而子进程创建它的子进程时又会将子进程的表给孙子进程, 所以说,环境变量具有全局性!


在bash中查看所有环境变量

在bash中查看所有环境变量:

使用指令: env

环境变量PWD: 

记录当前路径,你以为平时执行的pwd指令是怎么知道当前路径的?pwd实际上调用了PWD环境变量!

 环境变量HOME

我们平时使用的指令:cd ~进入家目录,环境变量HOME里面的内容就是家目录!

根据以上对环境变量的认识,我们发现登录xshell时我们账户登录后就会到 /root 或者 /home/用户名 目录下,这是因为在启动Linux时,OS帮我们做了一些事情

1.输入用户名,密码

2.认证信息是否正确

3.形成环境变量(PATH,PWD,等等)

4.根据用户名初始化HOME环境变量

6.进入家目录


 程序中获取环境变量的方式

使用函数: getenv()

printf("PATH = %s\n",getenv("PATH"));

即函数的参数是环境变量的名字, 返回值是环境变量的内容!


main函数的第三个参数解析

int main(int argc,char* argv[],char* env[])
第三个参数为env,是不是很熟悉?

第三个参数就是环境变量,它和第二个参数一样是指针数组,它指向环境变量表,环境变量表中的内容和在bash中使用env打印的一样!

到目前为止了解到,系统在启动程序时会给main函数提供两张表:

命令行参数表和 环境变量表

通过下面的代码查看环境变量表:

1 #include <stdio.h>
2 #include <stdlib.h>
3 int main(int argc,char*  argv[],char* env[])                                                                                                                                                                
4 {
5     
6     int i = 0;
7     for(;env[i];i++)
8     {
9         printf("env[%d] = %s\n",i,env[i]);
10     }
11     return 0;
12 }


本地变量&环境变量 

我们可以在bash中直接定义环境变量

使用指令: 环境变量名=内容

用户自己定义的环境变量是本地变量的而env并不能查看本地的环境变量,所以使用查找刚才定义的环境变量时,实际上会找不到! 

如果想要我们定义的环境变量被放在系统的环境变量表中应该怎么做?

使用指令: export 环境变量名

  还可以使用export直接定义环境变量:

本地变量的一般形式为: [名称] = [内容] ,其只能在当前bash进程的内部有效,也就是说,由bash创建的子进程就不能再使用这个本地变量,下面是利用fork函数的证明:

我们发现,一开始子进程并没有找到对应的本地变量的内容, export将变量导入环境变量表环境变量就可以供子进程使用了.

本地变量 VS 环境变量
1. 本地变量只在bash进程内部有效, 不会被子进程继承
2. 环境变量通过让所有子进程继承的方式, 实现自身的全局性


内建命令与常规命令 

我们发现像一些系统定义的命令,比如echo这种命令,却都能够获取本地变量的内容,众所周知,这些命令本质上也是bash所创建的一个子进程,按理来说,它们也应该获取不到本地变量的值才对,这是为什么呢?

在Linux中,命令分为常规命令(shell fork让子进程创建形成的)和内建命令(shell命令行的一个函数), 而这些简单而又安全的命令, 比如pwd,echo和export之类的命令可以作为shell的函数而在不创建子进程的同时读取shell本地的变量。echo是内建命令,是bash父进程自己内部执行的,所以它可以使用父进程的本地变量, 但是其他的子进程不能接受父进程的本地变量,所以无法读取!

我们知道一个事实,bash中的指令可以直接使用, 不用加./是因为它的路径在环境变量PATH中,所以我们将PATH置空后,这些常规命令就不能运行了!因为bash无法找到可执行程序的目录,如果我们想要运行一个可执行程序,需要告诉系统我们的可执行的目录,让系统自动找到可执行的目录得以执行程序。

echo等命令是内建命令,是shell命令函的一个函数, 可以直接执行还能读取shell内部定义的本地变量.

此时PATH设置为了空,上面说过可以重新登陆新建一个bash进程重新读取PATH变量, 这个时候, 我们再来测试环境变量myvarible还存不存在,会不会被重置

我们发现,环境变量又没了,这其实和我们上面添加环境变量处的情况相似,我们的bash解释器是将环境变量拷贝到了内存,而bash进程是在内存中运行的,我们对内存的所有操作,都会因为当前bash进程的退出(用户退出)而被销毁, 如果想一直保留新建的环境变量该怎么办呢?

从上面的原理中,我们知道了在用户登录的时候 .bash_profile 这个配置文件会识别用户属性然后为用户配置环境变量表和命令行参数表,那么,我们可以将我们的环境变量信息添加到这个配置文件中:

当我们再次重新登录用户,我们发现此时环境变量已经被保存了下来,并且能被我们查询到。 

当然,因为我们的配置文件是因用户而异的,也就是说,每一个用户的配置文件都不一定相同,所以,我们当前的配置,在其他用户下不能生效(包括root用户)。但是,对于同一个用户,只要我们修改了其配置文件,bash所有的子进程、孙子进程等进程都可以使用使用该环境变量了。

       所以,现在我们应该能大题了解了什么是环境变量,环境变量本质就是找到可执行程序的目录,如果我们想要运行一个可执行,需要告诉系统我们的可执行的目录,好让系统自动找到可执行的目录得以执行程序。

当然,因为我们的配置文件是因用户而异的,也就是说,每一个用户的配置文件都不一定相同,所以,我们当前的配置,在其他用户下不能生效(包括root用户)。但是,对于同一个用户,只要我们修改了其配置文件,bash所有的子进程、孙子进程等进程都可以使用使用该环境变量了。


通过第三方变量environ获取 

如果不给main函数穿第三个参数,通过environ变量也是可以访问环境变量的:

在Linux中,environ是一个全局变量,它是一个字符串数组,用于存储当前进程的环境变量。它是一个二级指针,每个指针指向一个以"key=value"形式表示的环境变量字符串。

environ变量被定义在C标准库的<unistd.h>头文件中,并由操作系统在程序启动时自动创建和初始化。它存储了操作系统为当前进程提供的环境变量的副本。通过environ变量,可以访问和操作当前进程的环境变量。例如,可以使用循环遍历environ数组,查看和修改环境变量的值。

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 int main()
 {
     extern char** environ;
     int i = 0;
     for(;environ[i];i++)
     {
         printf("我是进程%d,%s\n",getpid(),environ[i]);                                                                                                                                                      
     }
    return 0;
}

总结:目前有三种访问环境变量的方式:

1.echo $环境变量

2.通过main函数参数列表的第三个参数环境变量表来访问

3.通过environ来访问

一些其他关于环境变量的命令

 除了上面的export、env、echo等命令,我们再来介绍两个命令:

unset: 清除环境变量

set: 显示本地定义的shell变量和环境变量

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WIFI/BT中蓝牙的硬件资源是如何调度的 UART和PCM接口传输的是什么信号

安卓或IOS手机中&#xff0c;wifi/bt中的蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。M.2 wifi/bt模块或其他形式的模块中&#xff0c;蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。今天我们就图文并茂的解决这个问题。 蓝牙文件…

SQL 基础 | AS 的用法介绍

SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和操作数据库的标准编程语言。 在SQL中&#xff0c;AS关键字有几种不同的用法&#xff0c;主要用于重命名表、列或者查询结果。 以下是AS的一些常见用法&#xff1a; 重命名列&#xff1a;在SELECT语句中&a…

Vue生命周期都有哪些?

定义 Vue的生命周期就是实例从创建到销毁的一个过程&#xff0c;即从创建、初始化数据、编译模板、挂载Dom($el)->渲染、更新->渲染&#xff0c;卸载等一系列的过程。el是挂载点如<div id"app"></div>。 Vue的生命周期分为八个阶段 1.beforeCreate…

重看Spring聚焦BeanDefinition分析和构造

目录 一、对BeanDefinition的理解 &#xff08;一&#xff09;理解元信息 &#xff08;二&#xff09;BeanDefinition理解分析 二、BeanDefinition的结构设计分析 &#xff08;一&#xff09;整体结构体会 &#xff08;二&#xff09;重要接口和类分析 三、构造 BeanDef…

保姆级IDEA安装与配置教程(含视频+资料)

课程简介 本套课程主要针对 Java 基础开发相关的工具安装和使用&#xff0c;主要包含有 IDEA 的下载、安装、配置、使用、快捷键的使用等。 本套视频是作为新手最为实用的课程&#xff0c;IDEA 是 Java 企业级开发最为常用的继承开发环境。如果熟练使用 IDEA 的话&#xff0c…

【中断】【ARM64】学习总结

optee中的异常向量表解读–中断处理解读 https://mp.weixin.qq.com/s/gBsy4YDYTHGRsy2zcVr6Vg

c# winform快速建websocket服务器源码 wpf快速搭建websocket服务 c#简单建立websocket服务 websocket快速搭建

完整源码下载----->点击 随着互联网技术的飞速发展&#xff0c;实时交互和数据推送已成为众多应用的核心需求。传统的HTTP协议&#xff0c;基于请求-响应模型&#xff0c;无法满足现代Web应用对低延迟、双向通信的高标准要求。在此背景下&#xff0c;WebSocket协议应运而生…

Polardb集中式部署体验

前言说明 PolarDB是阿⾥云数据库团队⾃主开发的云原⽣数据库。据了解PolarDB是产品品牌统称&#xff0c;云上PolarDB提供了Polardb MySQL版&#xff08;集中式数据库&#xff09;&#xff0c;PolarDB PostgreSQL版&#xff08;集中式数据库&#xff09;和PolarDB分布式版&…

人工智能论文:BERT和GPT, GPT-2, GPT-3 的简明对比和主要区别

在BERT的论文里面&#xff1a; 2018.10 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding&#xff0c;BERT已经解释了BERT&#xff0c;GPT&#xff0c;ELMo的区别。 *ELMo为双向RNN&#xff0c;请忽略。 主要区别&#xff1a; BERT使用的是…

机器学习:深入解析SVM的核心概念【四、软间隔与正则化】

软间隔与正则化 问题一&#xff1a;优化目标函数是如何得到的&#xff1f;得到的过程是怎样的&#xff1f;问题二&#xff1a;拉格朗日乘子法计算详细过程问题三&#xff1a;KKT条件求解过程问题四&#xff1a;结构风险最小化&#xff08;SRM&#xff09;的原理 在前面的讨论中…

批量视频剪辑新选择:一键式按照指定秒数分割视频并轻松提取视频中的音频,让视频处理更高效!

是否经常为大量的视频剪辑工作感到头疼&#xff1f;还在一个个手动分割、提取音频吗&#xff1f;现在&#xff0c;我们为你带来了一款全新的视频批量剪辑神器&#xff0c;让你轻松应对各种视频处理需求&#xff01; 首先&#xff0c;进入媒体梦工厂的主页面&#xff0c;并在板…

机器学习之基于Tensorflow(LSTM)进行多变量时间序列预测股价

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介&#xff1a;机器学习之基于TensorFlow&#xff08;LSTM&#xff09;进行多变量时间序列预测股价 一、项目…

【Java从入门到精通】Java 正则表达式

目录 正则表达式实例 &#x1f349;java.util.regex 包 &#x1f349;实例 &#x1f349;捕获组 &#x1f349;实例 &#x1f349;RegexMatches.java 文件代码&#xff1a; &#x1f349;正则表达式语法 &#x1f349;Matcher 类的方法 &#x1f349;索引方法 &#…

【Qt QML】QLibrary加载共享库中的类

QLibrary是一个用于加载动态链接库&#xff08;或称为共享库&#xff09;的类。它提供了一种独立于平台的方式来访问库中的功能。 在QLibrary中&#xff0c;可以通过构造函数或setFileName()方法设置要加载的库文件名。当加载库文件时&#xff0c;QLibrary会搜索所有平台特定的…

消失的VCC和VEE,取而代之的VDD和VSS

一直以来&#xff0c;这些电源电压&#xff08;Vdd 和 Vss&#xff09;或&#xff08;Vcc 和 Vee&#xff09;的命名都有点耐人寻味&#xff0c;甚至令人困惑。但为什么呢&#xff1f; It has always been a bit intriguing and even confusing the nomenclature of these powe…

Unreal 编辑器工具 批量重命名资源

右键 - Editor Utilities - Editor Utility Blueprint&#xff0c;基类选择 Asset Action Utility 在类默认值内&#xff0c;可以添加筛选器&#xff0c;筛选指定的类型 然后新建一个函数&#xff0c;加上4个输入&#xff1a;ReplaceFrom&#xff0c;ReplaceTo&#xff0c;Add…

多国语言免费在线客服系统源码,网站在线客服系统,网页在线客服软件在线聊天通讯平台

详情介绍 多国语言免费在线客服系统源码,网站在线客服系统,网页在线客服软件在线聊天通讯平台 新款在线客服系统全开源无加密:多商户、国际化多语言、智能机器人、自动回复、语音聊天、 文件发送、系统强力防黑加固、不限坐席、国际外贸、超多功能 支持手机移动端和PC网页…

安装ESXI 7.0的系统盘小于120G,安装后无本地datastore存储的处理办法

1、应用场景 在全新安装ESXI 7.0后&#xff0c;系统将会划分120G空间作为虚拟闪存&#xff0c;在大容量硬盘的设备中&#xff0c;120G无足轻重&#xff0c;但是当ESXI系统盘容量非常小的时候会导致无可用本地存储空间。 我这里的情况就是服务器里内置了2个120G的硬盘&#xff…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《计及高阶方程分段线性化的港口电-氢综合能源系统优化调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

WPF之可翻转面板

1&#xff0c;创建翻转面板的资源字典&#xff1a;FlippPanel.xaml。 无外观控件同样必须给样式指定类型&#xff08; <ControlTemplate TargetType"ss:FlipPanel">&#xff09;&#xff0c;相关详情参考&#xff1a;WPF之创建无外观控件-CSDN博客&#xff09…