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变量和环境变量

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

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

相关文章

ABAP 第二代增强-采购申请子屏幕增强

文章目录 第二代增强-采购申请子屏幕增强需求实现过程创建项目运行效果客户屏幕的PBO全局变量获取数据更新数据运行效果查询底表修改数据 第二代增强-采购申请子屏幕增强 需求 实现过程 创建项目 运行效果 客户屏幕的PBO 全局变量 *&------------------------------------…

关于Docker的数据管理

文章目录 一、Docker的数据管理1、数据卷1.1 数据卷定义1.2 数据卷配置 2、数据卷容器2.1 创建数据卷容器2.2 使用--volume-from来挂载luck02 二、端口映射三、容器互联1、创建容器互联2、进入luck02测试&#xff08;ping 容器名/别名&#xff09; 四、Docker镜像的创建1、基于…

Java类文件.class详解

一、编译型语言和解释型语言的区别 1、编译型语言&#xff1a; 在编译型语言中&#xff0c;源代码会被整个编译成机器码或者中间代码&#xff08;比如Java的字节码&#xff09;&#xff0c;生成可执行文件。 运行程序时&#xff0c;不需要再对源代码进行解释&#xff0c;而是…

RockChip Android13 NFC SL6320移植

环境:RK3568 Android13 一:驱动移植 1、驱动 将SL6320驱动代码拷贝至kernel-5.10/drivers/misc/sl6320/ 特殊说明:勿将驱动代码放置于kernel-5.10/drivers/nfc/目录下,会导致sl6320驱动生成设备节点时因/dev/nfc节点以创建而加载失败。 2、DTS 本次硬件设计电路走I2C协…

服务器数据恢复—多块磁盘离线导致阵列瘫痪,上层lun不可用的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌MSA2000存储&#xff0c;该存储中有一组由8块SAS硬盘&#xff08;其中有一块热备盘&#xff09;组建的RAID5阵列&#xff0c;raid5阵列上层划分了6个lun&#xff0c;均分配给HP-Unix小型机使用&#xff0c;主要数据为oracle数据库和O…

【LeetCode刷题】34. 在排序数组中查找元素的第一个和最后一个位置

1. 题目链接 34. 在排序数组中查找元素的第一个和最后一个位置 2. 题目描述 3. 解题方法 找到元素的第一个位置&#xff0c;也就是找大于等于目标的最小值找到元素的最后一个位置&#xff0c;也就是找小于等于目标的最大值可以利用2次二分查找来解决 3.1. 第一次查找 3.2. …

今日详解,教你如何不直播在视频号卖货

大家好&#xff0c;我是电商笨笨熊 视频号作为背靠微信的平台&#xff0c;从不需要考虑自身的流量问题&#xff0c; 因此在视频号推出之后就有大批的主播从其他平台转入视频号&#xff1b; 而这时候很多普通人应该也发现了新的机会&#xff0c;不再去内卷抖音、快手直播&…

【Git】Github创建远程仓库并与本地互联

创建仓库 点击生成新的仓库 创建成功后会生成一个这样的文件 拉取到本地 首先先确保本地安装了git 可以通过终端使用 git --version来查看是否安装好了git 如果显示了版本信息&#xff0c;说明已经安装好了git&#xff0c;这时候我们就可以进入我们想要clone到问目标文件夹 …

python-正则表达试-实践1

匹配html标签中的任意标签内数据 匹配所有包含’oo’的单词 import re text "JGood is a handsome boy, he is cool, clever, and so on..." re.findall(r\w*oo\w*, text) 匹配 html中title里面的内容 原文&#xff1a; import re file r./202304.html f open(…

2023数维杯A题原创完整论文思路和求解代码

河流对地下水有着直接地影响,当河流补给地下水时,河流一旦被污染,容易导致地下水以及紧依河流分布的傍河水源地将受到不同程度的污染,这将严重影响工农业的正常运作、社会经济的发展和饮水安全。在地下水污染中最难治理和危害最大的是有机污染,因而对有机污染物在河流-地下…

WordPress Automatic插件 SQL注入漏洞复现(CVE-2024-27956)

0x01 产品简介 WordPress Automatic(又称为WP Automatic)是一款流行的WordPress插件,旨在帮助网站管理员自动化内容创建和发布。该插件可以从各种来源(如RSS Feeds、社交媒体、视频网站、新闻网站等)获取内容,并将其自动发布到WordPress网站。 0x02 漏洞概述 WordPres…

从论文中看AI绘画

个人博客:Sekyoro的博客小屋 个人网站:Proanimer的个人网站 主要看是看Diffusion Models,CLIP,ControlNet,IP-Adapter这种经典论文,尝试总结论文写作的一些方式以及图像生成模型的一些内在思想. 对于其中的数学原理和代码不过深究. DDPM 使用扩散模型得到高质量图像,证明了这…

“给力”用日语怎么说?柯桥成人日语培训

在日语中,给力这个词可以翻译成几个不同的表达方式,具体取决于语境。以下我将给出几个常见的日语翻译以及例句帮助理解: スゴイ 这个词意思为“太棒了”,是表达给力的最常见说法。 例如: これはスゴイ映画だね。这电影太给力了! 最高 意思为“最棒的”,也可以用来表达给力。 例…

连锁店收银系统为什么贵

连锁店收银系统会比单机收银系统价格高一些&#xff0c;主要有三个方面的原因&#xff1a; 复杂的功能需求 连锁店收银系统需要管理多个分店的进销存、库存调拨、门店订货等操作&#xff0c;以及会员管理&#xff0c;商淘云连锁收银系统还提供了连锁线上商城等功能。这些功能的…

“胖猫”事件

1.她自以为手段高明&#xff0c;不过是他心甘情愿罢了。 2. 可惜他在最后一刻&#xff0c;也没怨恨过她。 3.她反复确定用不用还&#xff0c;他反复确定有没有爱。 4. 他才21岁&#xff0c;只想见你一面&#xff0c;有什么错。 5. 希望你学会爱的时候&#xff0c;爱的第一个人是…

csrf攻击(跨站请求伪造)【2】

1.DVWA中csrf漏洞验证low &#xff08;1&#xff09;受害者将密码更改为password&#xff0c;显示更改成功 (2)受害者未退出登录状态&#xff0c;打开了新链接(黑客设计好的修改密码为admin123(原本为passwrod)的链接&#xff09;&#xff0c;导致受害者密码被更改&#xff0c…

Python-VBA函数之旅-pow函数

目录 一、pow函数的常见应用场景 二、pow函数使用注意事项 三、如何用好pow函数&#xff1f; 1、pow函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a;神奇夜光杯-CSDN博客 一、pow函数的常见应用场景 Py…

【Web】CTFSHOW 中期测评刷题记录(1)

目录 web486 web487 web488 web489 web490 web491 web492 web493 web494 web495 web496 web497 web498 web499 web500 web501 web502 web503 web505 web506 web507 web508 web509 web510 web486 扫目录 初始界面尝试文件包含index.php&am…

COUNT(1)\COUNT(*)\COUNT(列名)到底谁更快

今天来研究一个比较有趣的话题,关于我们平常使用mysql查询数量的到底那种方式查询效率更高的问题 起因 这个问题在我以前的认知里是,按效率从高到低品排序 count(1)>count(列名)>count(*),但是我也注意到过mybatis-plus官方提供的selectCount方法和分页查询时,它的SQL在…

Linux(openEuler、CentOS8)企业内网DHCP服务器搭建(固定Mac获取指定IP)

----本实验环境为openEuler系统<以server方式安装>&#xff08;CentOS8基本一致&#xff0c;可参考本文&#xff09;---- 目录 一、知识点二、实验&#xff08;一&#xff09;为服务器配置网卡和IP&#xff08;二&#xff09;为服务器安装DHCP服务软件&#xff08;三&a…