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

【Linux系统】13. 命令行参数 环境变量

一. 命令行参数

1)main函数可以有参数么?

可以的。根据我们学语言的经验,应该是见过main函数的参数。

#include <stdio.h>int main(int argc, char *argv[])
{return 0;
}

运行之后没有报错,是可以带参的。

2)这个参数是什么?

1. argc(argument count)
整型变量,表示命令行参数个数,因为包括程序名本身,所以它的值至少为1,即argc >= 1。
2. argv(argument vector)
字符指针数组,他的元素是一个字符串,代表一个命令行参数。第一个元素 argv[0] 是程序自身的名字。最后一个元素 argv[argc] 是一个空指针NULL,标志参数列表的结束。
3. 打印出来看一下

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


① 在命令行中输入命令本质是一个字符串,shell以空格为分隔符,将这个字符串转化为若干子串。有多少子串,argc就是几。
② 拆分字符串和设置填充argc、argv的工作是由bash和系统自动完成的,我们看不到。
③ main函数的参数通常被称为命令行参数。 我们在bash中输入的字符串也叫命令行参数,他们是同一概念的不同阶段。只不过main函数的参数是被处理过的。

3)为什么要有命令行参数?

命令行参数的本质应用是为了,实现命令可以根据不同的选项实现不同的子功能。这也就是Linux中所有命令选项功能的实现方式。

#include <stdio.h>
#include <string.h>int main(int argc, char *argv[])
{if(argc != 2){printf("错误使用!正确用法:%s -a | -b | -c | -d\n", argv[0]);return 1;}if(strcmp(argv[1], "-a") == 0){printf("使用的是第一种功能\n");}else if(strcmp(argv[1], "-b") == 0){printf("使用的是第二种功能\n");}else if(strcmp(argv[1], "-c") == 0){printf("使用的是第三种功能\n");}else{printf("使用的是默认功能\n");}return 0;
}

4)其他细节

1. 选项是以空格为分隔的字符串,一个字符也是字符串。
2. argv表的最后一个元素是NULL,所以最有一个有效子串是argc[argc - 1]。NULL作为数组结束的标志可以用来做循环判断条件。

for(int i = 0; argv[i]; i++)
{printf("argv[%d]->%s\n", i, argv[i]);
}

证明:

#include <stdio.h>int main(int argc, char *argv[])
{if(argv[argc] == NULL){printf("== NULL\n");}return 0;
}

5)VS2022(Windows下)有命令行参数么?

有的。命令行参数在所有平台下都有,因为他是语言的特点。VS2022中可以配置。

6)cat file.txt 获取文件内容的方式

cat 命令也是用C语言写的,首先fopen打开文件,此时就要获取文件名。file.txt就是作为命令行参数传到程序中。

二. 环境变量

1)概念

1. 环境变量(environment variables)一般是指在操作系统中,用来指定操作系统运行环境的一些参数。
如在编译C/C++代码,链接时,我们从来不知道链接的动静态库在哪,但是照样可以链接成功,就是因为有环境变量告诉编译器去哪里找。
2. 环境变量通常具有特殊用途,在系统当中通常具有全局性。
3. 环境变量有很多,其中有一个非常重要的 -- PATH。

2)PATH

#include <stdio.h>int main()
{printf("my command!\n");return 0;
}


我们之前说过其实系统命令就是特定路径(/usr/bin/)下的普通文件,那为什么我们的普通文件必须要加./才能运行,而系统命令可以直接运行?
因为系统在找可执行程序时默认到 /usr/bin/ 下找,我们自己写的程序系统找不到。
只要添加到特定路径就可以不加./直接运行。

1. Linux系统怎么知道要到哪个路径下找可执行程序?

① 因为Linux系统中存在一个环境变量PATH。PATH是变量名,想查看他的内容要加个$,有点类似指针和解引用。

② 它的内容是以 冒号: 为分隔符的一串路径。
③ 他的作用是指定命令的搜索路径。告诉Linux系统,如果用户要执行一个可执行文件但没有指明路径,就到PATH中的路径一个一个找,找不到就通过bash告诉用户。

2. 所以还有一种方法可以不加./就运行自己的可执行程序,就是将自己的可执行程序放到PATH中。
① 错误做法:

那之前的PATH找不回来了怎么办,直接关闭XShell,重新登录就自动刷新了,怎么做到的之后说。

② 正确做法:

3. Windows中也有环境变量这个概念,他的PATH作用和Linux一样。



可以看到D:\XShell\这个路径在我们系统的环境变量中,说明我们想要执行XShell.exe这个可执行程序时,只要直接输入名字就可以执行。
打开Windows的命令行尝试一下:



现在我们也想直接通过命令行打开chrome,发现不行,因为chrome并不在path中。

那就将chrome的路径添加到path中:

重新打开cmd:

3)更多环境变量

1. 环境变量往往是全局的,有变量名和变量内容,具有全局属性(要么是系统全局的,要么是用户全局的)
2. 除了PATH还有其他很多环境变量。

1. env命令 -- 查看系统中所有环境变量。

[lsy@hcss-ecs-116a code_env]$ env
XDG_SESSION_ID=4193
HOSTNAME=hcss-ecs-116a
TERM=xterm
SHELL=/bin/bash
HISTSIZE=10000
SSH_CLIENT=112.54.13.165 4473 22
SSH_TTY=/dev/pts/0
USER=lsy
LD_LIBRARY_PATH=:/home/lsy/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/lsy
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lsy/.local/bin:/home/lsy/bin
PWD=/home/lsy/code/code_env
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/lsy
LOGNAME=lsy
SSH_CONNECTION=112.54.13.165 4473 172.31.1.73 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/1000
HISTTIMEFORMAT=%F %T lsy 
_=/usr/bin/env
OLDPWD=/home/lsy

2. HOSTNAME=hcss-ecs-116a:当前机器对应的主机名,这就是为什么我们的命令行提示符知道主机名是什么。

3. TERM=xterm:当前终端类型。
4. SHELL=/bin/bash:当前用的是什么版本的shell,bash是一种具体的shell。
5. SSH_CLIENT=112.54.13.165 4473 22:客户端信息。
6. SSH_TTY=/dev/pts/0:同一用户可以打开多个终端,SSH_TTY记录当前是哪个终端文件。这就是问什么我们echo打印一个字符串,他知道往哪个终端打。

7. USER=lsy:登录用户。这就是为什么whoami就能知道我们是谁。

8. LD_LIBRARY_PATH=:/home/lsy/.VimForCpp/vim/bundle/YCM.so/el7.x86_64:动态库查找路径。
9. LS_COLORS:配色方案。
10. MAIL=/var/spool/mail/lsy:邮件。
11. PATH:指定命令的搜索路径。
12.PWD:每次切换记录当前工作路径。环境变量是一个变量,随着你所处环境的改变,他们是会变的。

13. HOME=/home/lsy:记录家目录。
14. LOGNAME=lsy:登录用户。

15. HISTSIZE=10000

① 我们在Linux下,按键盘的上下键就可以快速调出历史命令,这就说明Linux一定是把那些命令记录下来了。
② history 命令 --- 打印历史命令。


③ HISTSIZE是Linux能记住的最多的指令数,但超过就会丢弃最之前的,也就是只记录最近的10000行。
④ wc -l 可以统计有多少行。

history | wc -l

wc(word count):默认输出四个信息 -- 行数、单词数、字节数、文件名。
-l 选项:只显示行数。

16. OLDPWD:最近一次路径。
之前我们 cd - 就能回到最近一次路径,那系统是如何找到这个最近一次的路径的?就是通过环境变量OLDPWD中的记录。即输入命令 cd - 会被解释成cd $OLDPWD。

4)用代码获取环境变量

1. 方法一:main函数的参数

main函数的参数最多有三个,之前我们只介绍了两个,第三个就可以帮我们获取环境变量。

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

打印出来看一下:

#include <stdio.h>int main(int argc, char *argv[], char *env[])
{// 变量不用有些编译器会有警告// 这样强转一下就不会有了(void)argc;(void)argv;int i = 0;// env最后一个元素也是NULL,所以也直接用来做条件判断了for(; env[i]; i++){printf("env[%d] = %s\n", i, env[i]);}return 0;
}

① 运行程序得到的就是系统环境变量。
② env[]是环境变量表,做main函数的参数就是把环境变量表传递给进程。
③ 命令行参数表和环境变量表都交给进程。

2. 方法二:全局变量 -- environ

其实没有main函数的参数我们也能获取环境变量,语言提供了直接指向环境变量表的全局变量:char **environ,可以获取到所有的环境变量。要包头文件 <unistd.h>。

#include <stdio.h>// int main(int argc, char *argv[], char *env[])
int main()
{// 声明一下,不然链接的时候可能找不到extern char **environ;int i = 0;// env最后一个元素也是NULL,所以也直接用来做条件判断了// env 和 environ都是二级指针for(; environ[i]; i++){printf("envrion[%d] -> %s\n", i, environ[i]);}return 0;
}


3. 方法三(最常用):getenv -- 通过名字获取一个环境变量

① 根据名字直接获取环境变量的内容,如果传的环境变量名不存在,则返回NULL。
② 原理就是拿传过来的名字遍历env表,用名字和等号左边对比,若匹配成功则返回等号右边,不成功返回NULL。
③ 使用

#include <stdio.h>
#include <stdlib.h>
#include <string.h>int main()
{char *whoami = getenv("USER");printf("whoami:%s\n", whoami);if(whoami == NULL){printf("用户名获取失败,你无权执行\n");return 0;}else if(strcmp(whoami, "root") == 0)printf("root用户也不能执行\n");else if(strcmp(whoami, "lsy") == 0)printf("lsy可以执行!\n");else{printf("非法用户,不可执行\n");}return 0;
}

  • 执行的时候注意切换到root要重新开一个终端并登陆root账号,或者用su -,不能直接用su。
    因为,su启动的是一个非登录shell,环境变量大部分继承原用户而不是切换到新用户的完整环境,结果就是USER不变,执行程序时getenv得到的还是lsy而不是root。因为 su 设计的初衷就是在当前会话环境中临时切换身份来执行任务,而不是模拟一次完整的重新登录。
    su - 就会启动一个登录shell。
  • 利用环境变量的用户名可以区分设置某些功能谁能做谁不能做,或者某台主机、某个终端、某个路径等能做不能做。这样写出来的软件可以和系统做相关,针对用户、主机、路径等。
  • 综上可知,不同环境变量会有不同的应用场景,所以我们要获取它。

4. 总结

获取环境变量的三种方法
① main函数参数 -- char *env[]
② C语言全局变量 -- char **environ
③ 最佳时间 -- getenv

5)环境变量的全局性

1. 我们前面说main函数的第三个参数本质是把环境变量表传给进程,那么这个传递工作是谁做的呢?
① 是父进程。
② argv 和 env这两张表默认都在bash内部,是bash进程的数据。bash作为一个进程是放在内存中的,所以这两张表也是放在内存里的,是临时表,内存级别的。
③ 我们自己的程序、命令等都是bash进程的子进程,父子进程共享代码和数据,子进程可以看到bash的数据,所以即使main函数不传,我们也可以通过environ或者getenv等命令获取。

2. bash的子进程可以再去fork它的子进程,这个新的子进程依旧可以共享继承到那两张表,所以就这样传递着,bash的所有子孙进程都可以看到环境变量表,这就是环境变量具有全局属性的原因。

6)环境变量配置文件

1. 如果bash的子进程都是从bash获取的环境变量,那么bash的环境变量又是从哪来的?
从Linux系统的配置文件里来。bash在启动之前要读取配置文件,把信息加载到自己的上下文。大概过程就是:bash这个程序启动之前,fopen打开配置文件,按行读取文件内容并转换成字符串,分别放到new出来的char *env[]的 env[0], env[1], env[2]....中。

2. 这就能解释为什么刚刚我们将环境变量覆盖了,只要重新登录就恢复了?
因为我们的修改只是临时修改了当前bash进程在内存中的环境变量值,并没有写入配置文件。所以重新登录之后,bash要重新读取并加载环境变量的内容。

3. 配置文件在哪?
在家目录的隐藏文件中,这也是为什么每个用户都要有自己的家目录,因为家目录里放着各自的配置文件。

我们可以打开看一下:

那我们就打开 .bashrc 文件看一下:

再去访问 /etc/bashrc:这个文件内部也全都是shell脚本写的,比较复杂,其实他的内部还会访问更多文件,但是我们只需要知道,最终我们需要的环境变量都会被在这里定义好就可以了。



4. 验证bash每次启动前都会加载这个配置文件:修改一下配置文件,重新登录看效果。



果然,重新登录后我们配置过的东西都出现了。但是我们配置的是用户自己的配置文件,当以其他用户身份登录时就不会有了:以root为例。

7)环境变量 && 本地变量

1. 创建一个自己的环境变量


这种直接在命令行上用等号定义的变量叫本地变量(或普通变量),他并不是真正的环境变量。


正确做法 -- export:本质是在当前bash的环境变量表中插入一个变量,也是内存级的。
① 对于已经存在的变量:

② 对于不存在的变量:


我们已经导入了两个变量到env表中,他们能否被我们的C语言程序获取呢?
是能的。导出完立即就可以用。

#include <stdio.h>
#include <stdlib.h>int main()
{printf("MY_ENV:%s\n", getenv("MY_ENV")); // 存在printf("MYENV:%s\n", getenv("MYENV")); // 不存在return 0;
}


子进程能获取父进程的环境变量,环境变量可以被子进程继承,所以环境变量是全局的。

2. 删除我们自己导入的环境变量

① unset + 环境变量名。
② 把我们刚刚导入的两个环境变量删掉。

3. 和环境变量相关的命令总结

① echo $环境变量名:显示某个环境变量的值。
② export:设置一个新的环境变量。
③ unset:清除环境变量。
④ env:只显示所有的环境变量。
⑤ set:显示所有的本地变量和环境变量。

这些命令对环境变量的影响都是内存级别的,不影响配置文件,可以随便用随便改,只要重新登录就全都恢复了。

4. 本地变量的特点

本地变量无法被子进程继承,不具有全局性,只可以在bash内部访问。
本地变量和环境变量 可以类比成C/C++中的 局部变量和全局变量。

#include <stdio.h>
#include <stdlib.h>int main()
{printf("IF_EXTEND:%s\n", getenv("IF_EXTEND"));return 0;
}

5. 本地变量有什么用

与shell脚本有关,可做条件判断或者记录信息等。
其实我们在学习指令需要快速生成多行文本时就用过。

cnt=0; while [ $cnt -le 100 ]; do echo $cnt; let cnt++; done


6. 彻底将本地变量导出成环境变量 -- 改 .bash_profile




8)内件命令(大致了解)

1. 两个现象
① echo命令是bash的子进程;local_value 是本地变量;本地变量无法被子进程继承;那么,echo是如何找到 local_value 并打印的呢?

② 将PATH变量清空,我们知道PATH指明了命令的搜索路径,清空后bash找不到指令,也无法执行,但是为什么有一些命令还能用?

2. 通过上面两个现象我们发现命令和命令之间是不一样的:
① 普通命令:存在特定路径下的二进制文件。
② 内建命令:在shell内部自己定义的,可以理解为bash的一次函数调用,bash也是C语言写的,内部一定有很多函数。这种命令不依赖第三方路径。
③ 这里先大致了解一下内建命令,之后细讲。

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

相关文章:

  • 中山免备案网站建设wordpress安装说明seo工具好用
  • 免费个人二级域名网站西安设计工作室
  • SQL plus中解决上下键找历史命令的工具--rlwrap命令行工具
  • 基于微服务脚手架的视频点播系统 (仿B站) [客户端] -1
  • 做网站销售电销好做吗网站建设投标书免费
  • 创建网站要钱吗优惠好券省钱必逛 查看详情 prime会员甄选 查看详情
  • uni-app app移动端实现纵向滑块功能,并伴随自动播放
  • Nacos-服务发现
  • 西安网站建设有限公司上海网站建设的意义
  • 网站推广新手入门h5自己制作模板
  • 广西网站建设定制阿里云备案网站负责人
  • 做网站长沙如何去掉wordpress
  • Netty详解-01
  • 我公司让别人做网站了怎么办个人微信公共号可以做微网站么
  • 做网站 发现对方传销兴义 网站建设
  • 节点小宝免费版流量机制解析:点对点直连技术与备用流量设计
  • 扁平化网站源码企业网站的建立费用 作什么科目
  • 卖货网站平台互联网o2o是什么意思
  • 网站建设需要通过哪些审批大同住房和城乡和建设网站
  • 做个企业网站要多少钱网络的推广
  • 一套随访系统源码,医院随访管理系统源码,三级随访平台源码,技术框架:Java+Spring boot,Vue,Ant-Design+MySQL5
  • 响应式网站开发现状宁波高端网站建设推广
  • 摄影网站网页设计网络营销的特征包括
  • 潍坊模板建站定制网站优惠做网站
  • 共筑网络安全,守护绿色家园
  • 一枚指纹,开启工业IoT设备安全与权限分级实践
  • 设计电子商务网站建设方案住建房官网查询
  • 响应式网站做mip小程序什么样才能移到微信上
  • GIS-gdal-java.lang.NoSuchMethodError
  • 注册安全工程师考试科目南京seo顾问