命令行参数
命令行参数是什么?
命令行参数:
- 命令行中给定的参数。
- 每个命令行参数都是一个字符串,所有的命令行参数用指针数组存起来。
C/C++程序中,main
函数有2个参数,int argc
,char** argv
,其中argc
是命令行参数的个数,argv
指向第一个命令行参数。
我们通过下面代码查看一下命令参数中存放的是什么:运行程序时多输入几个命令,看看是不是所有命令都会被当作命令行参数传给main函数:
对于命令行参数:
- 运行程序时输入的指令会通过空格分割成
argc
字符串穿给main
函数的argv
参数,该参数为命令行参数。 argv
是一个指针数组,也就是一个二级指针。argv
数组最后一个元素一定是NULL
为什么要有命令行参数?
命令行参数可以让我们通过不同的指令使同一个代码执行不同的功能!
例如当我运行程序时输入
- 1 2 +程序返回3
- 1 2 - 程序返回-1
- 1 2 * 程序返回2
- 1 2 / 程序返回0
可以通过命令行参数这么实现:
在Linux系统中,存在大量的指令,每一个指令都有很多个参数在Linux系统中,一切皆为文件,包括指令。当我们输入指令时,操作系统会启动与该指令对应的进程。由于操作系统是使用C语言编写的,因此指令的逻辑代码通常通过
main
函数调用。当我们输入指令的选项时,main
函数将接收命令行参数。在指令对应的源代码文件中,不同的命令行参数将触发执行不同的功能。因此,可以说命令行参数是Linux指令选项实现的基础!
环境变量
环境变量概念
操作系统是一个开机时会自动启动的巨大的程序(软件),我们运行的程序都是操作系统进程的子进程,在操作系统中定义了一种包含关于系统路径、用户信息等属性的变量,这种变量称作环境变量。
环境变量是在操作系统级别上定义的一种变量,因为操作系统是一个程序,所以可以定义变量。
我们运行的程序可能会需要获取一些外部的信息或配置,这是可以通过环境变量提供这些信息。
定义环境变量的本质就是操作系统在内存中开辟一段空间并且赋值。
通俗一点理解:可以将操作系统看作是一个“家庭”,其中的进程是“家庭成员”。环境变量就像是这个“家庭”的共享财产,包括房子和车子。当家庭成员(进程)需要使用房子或车子时,它们可以通过访问共享财产(环境变量)来获取所需的信息。
总结:环境变量是操作系统内置的变量,用于于指定操作系统运行环境的参数。
初见环境变量
环境变量不是一个,而是一堆。彼此没有关系,有的记录当前路径、有的记录你是谁。
PATH:用于搜索指令对应的可执行程序文件路径的环境变量。
HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录。
SHELL : 当前Shell,它的值通常是/bin/bash
。
指令env可查看系统中所有环境变量:
[sy1@VM-16-11-centos 1_19]$ env
XDG_SESSION_ID=270847
HOSTNAME=VM-16-11-centos #主机名
SHELL=/bin/bash #命令行解释器
TERM=xterm
HISTSIZE=3000
OLDPWD=/home/sy1
USER=sy1 #当前用户名
/.../ # 其他的环境变量
PATH:用于搜索指令对应的可执行文件路径
运行自己的程序时我们需要使用相对路径或者绝对路径,但是使用系统指令时(ls、pwd各种指令), 可以直接运行而不需要指定路径/bin/指令名
(指令的可执行文件存放在/bin目录下)运行,这是因为指令对应的可执行文件所在路径已经被内置到环境变量中,运行该程序时操作系统会在该变量中搜索,存放可执行程序路径的变量是PATH
环境变量。
[sy1@VM-16-11-centos 1_19]$ /bin/ls #指定路径
code code.c makefile ocde.c Path Path.c
[sy1@VM-16-11-centos 1_19]$ ls #在PATH中寻找ls可执行程序对应的路径,找到后按照该路径执行
code code.c makefile ocde.c Path Path.c
指令echo $环境变量名
查看环境变量内容:
[sy1@VM-16-11-centos 1_19]$ echo $PATH #查看PATH变量的内容
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/sy1/.local/bin:/home/sy1/bin
#转换为列表
/usr/local/bin
/bin
/usr/bin
/usr/local/sbin
/usr/sbin
/home/sy1/.local/bin
/home/sy1/bin
说明:路径之间用:
分隔,当在bash中不带绝对路径执行指令时,OS会在PATH
环境变量中的路径从上往下搜索,在某一个路径中搜索到后停止搜索,执行该路径下的指令。即使5-10行的路径都有ls程序,若在第4行的路径发现了ls程序,就不会执行5-10行的ls程序了。
我们想将自己的程序不带绝对路径而输入程序名直接运行有两种做法:
-
将自己程序的可执行文件拷贝到上述任意一个路径中
[sy1@VM-16-11-centos 1_19]$ sudo mv ./Path /usr/bin #/usr/bin目录是被root管理的,需要提权 [sudo] password for sy1: #输入当前账户密码 .......... [sy1@VM-16-11-centos 1_19]$ Path #Path对应的可执行文件添加到/usr/bin目录下了,OS能在PATH中找到该文件 argv[0]:Path
这种做法不推荐。我们自己写的程序一般都是个半成品,这样会污染系统的
命令池
。 -
将自己程序的可执行文件的路径添加到环境变量中
[sy1@VM-16-11-centos 1_19]$ export PATH=/home/sy1/1_19:$PATH #像PATH中添加Path可执程序的路径 [sy1@VM-16-11-centos 1_19]$ echo $PATH #路径已经被添加到PATH中 /home/sy1/1_19:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/sy1/.local/bin:/home/sy1/bin [sy1@VM-16-11-centos 1_19]$ Path argv[0]:Path
指定
export
可添加环境变量export 变量名=val
—>让val覆盖变量内容,若环境变量不存在创建该环境变量。export 变量名=val:$变量名
—>让像变量内容中添加val。
- 环境变量是系统内置的具有特殊用途的变量
定义变量的本质其实是开辟空间,而变量只是这块空间的一个名字,在运行期间我们的程序也能开辟空间。
操作系统/bash可以在运行中开辟空间,系统的环境变量本质就是系统自己开辟空间,给它名字和内容即可!环境变量是系统开辟的一段空间。
HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)。
当我们使用命令su - 用户名 时,系统会自动为我们切换到当前用户的家目录下,这是因为切换用户时,操作系统为当前用户设置了HOME环境变量,将用户登录的路径设置为HOME变量值。
[root@VM-16-11-centos 1_19] su - root # 切换到root账户
Last login: Fri Jan 19 16:01:38 CST 2024 on pts/0
[root@VM-16-11-centos ~] pwd # 当前路径为root家目录
/root
[root@VM-16-11-centos ~] echo $HOME # root账户下的HOME环境变量
/root
[root@VM-16-11-centos ~] su - sy1 # 切换sy1账户
Last login: Fri Jan 19 09:34:10 CST 2024 on pts/0
[sy1@VM-16-11-centos ~]$ pwd # 当前路径为sy1家目录
/home/sy1
[sy1@VM-16-11-centos ~] echo $HOME # sy1账户下的HOME环境变量
/home/sy1
PWD:存放当前路径的环境变量
指令pwd之所以可以查看当前所在路径,是环境变量PWD存储的当前路径,而pwd进程中会读取PWD从而打印出当前路径:
[sy1@VM-16-11-centos ~]$ echo $PWD
/home/sy1
[sy1@VM-16-11-centos ~]$ pwd
/home/sy1
环境变量的相关知识扩展
永久添加环境变量
前面说过,export
命令可以修改环境变量的值。但环境变量是操作系统运行时初始化的变量,即每次开机后都会初始化,所以当我们使用export
命令修改环境变量后,下次开机时环境变量又被重新初始化了,我们export
的环境变量不存在了。
[sy1@VM-16-11-centos ~]$ export MYENV=aaaaaaa #导入环境变量
[sy1@VM-16-11-centos ~]$ echo $MYENV
aaaaaaa
#重新开机
[sy1@VM-16-11-centos ~]$ echo $MYENV
#MYENV环境变量不存在了
环境变量是内存级别的变量,每次操作系统启动时都会重新初始化。
环境变量的初始值是通过~/.bash_profile
文件确定的,即操作系统启动时会扫描当前用户目录下的.bash_profile
文件来初始化环境变量。
[sy1@VM-16-11-centos ~]$ pwd
/home/sy1
[sy1@VM-16-11-centos ~]$ cat .bash _pr
cat: .bash: No such file or directory
cat: _pr: No such file or directory
[sy1@VM-16-11-centos ~]$ pwd
/home/sy1
[sy1@VM-16-11-centos ~]$ cat .bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
想要永久更改某个用户的环境变量需要修改用户目录下的.bash_profile
文件,例如在/home/sy1/.bash_profile最后加上:
MYENV=aaaaaa
export MYENV
每次开机时操作系统就会添加环境变量MYENV啦
Last login: Fri Jan 19 19:00:52 CST 2024 on pts/0 #重新开机
[sy1@VM-16-11-centos ~]$ echo $MYENV #OS创建并初始化环境变量MYENV
aaaaaa
环境变量的组织方式
其实main函数可以有3个参数,除了命令行参数argc和argv以外,还有第三个参数char** env,env指向环境表(环境变量表),env和argv都是指针数组,argv的每一个元素是命令行参数,env的每一个元素是环境变量。
通过下面代码来看看env指向的环境具体是什么样子的:
#源文件
[sy1@VM-16-11-centos 1_19]$ cat Path.c
#include <stdio.h>
int main(int argc, char** argv, char** env)
{
for (int i = 0; env[i]; i++)
{
printf("env[%d]:%s\n", i, env[i]);
}
return 0;
}
#运行结果
[sy1@VM-16-11-centos 1_19]$ ./Path
env[0]:XDG_SESSION_ID=271682
env[1]:HOSTNAME=VM-16-11-centos
env[2]:SHELL=/bin/bash
env[3]:TERM=xterm
env[4]:HISTSIZE=3000
env[5]:USER=sy1
env[6]:LD_LIBRARY_PATH=:/home/sy1/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[7]: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:
env[8]:MAIL=/var/spool/mail/sy1
env[9]:PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/sy1/.local/bin:/home/sy1/bin
env[10]:MYENV=aaaaaa
env[11]:PWD=/home/sy1/1_19
env[12]:LANG=en_US.utf8
env[13]:SHLVL=1
env[14]:HOME=/home/sy1
env[15]:LOGNAME=sy1
env[16]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[17]:PROMPT_COMMAND=history -a; history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
env[18]:HISTTIMEFORMAT=%F %T
env[19]:_=./Path
env[20]:OLDPWD=/home/sy1
这些环境变量恰好是在bash中输入env指令得到的环境变量。
环境变量是可以被子进程继承的
[sy1@VM-16-11-centos 1_19]$ cat Path.c #Path.c创建子进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char** argv, char** env)
{
pid_t id = fork();
if (id == 0)
{
int i = 0;
printf("我是子进程\n");
for (i = 0; env[i]; i++)
{
printf("env[%d]:%s\n", i, env[i]);
}
return 0;
}
else{
int i = 0;
printf("我是父进程\n");
for (i = 0; env[i]; i++)
{
printf("env[%d]:%s\n", i, env[i]);
}
return 0;
}
}
[sy1@VM-16-11-centos 1_19]$ ./Path #运行Path
我是父进程
env[0]:XDG_SESSION_ID=271682
env[1]:HOSTNAME=VM-16-11-centos
env[2]:SHELL=/bin/bash
env[3]:TERM=xterm
env[4]:HISTSIZE=3000
env[5]:USER=sy1
env[6]:LD_LIBRARY_PATH=:/home/sy1/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[7]: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:
env[8]:MAIL=/var/spool/mail/sy1
env[9]:PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/sy1/.local/bin:/home/sy1/bin
env[10]:MYENV=aaaaaa
env[11]:PWD=/home/sy1/1_19
env[12]:LANG=en_US.utf8
env[13]:SHLVL=1
env[14]:HOME=/home/sy1
env[15]:LOGNAME=sy1
env[16]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[17]:PROMPT_COMMAND=history -a; history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
env[18]:HISTTIMEFORMAT=%F %T
env[19]:_=./Path
env[20]:OLDPWD=/home/sy1
我是子进程
env[0]:XDG_SESSION_ID=271682
env[1]:HOSTNAME=VM-16-11-centos
env[2]:SHELL=/bin/bash
env[3]:TERM=xterm
env[4]:HISTSIZE=3000
env[5]:USER=sy1
env[6]:LD_LIBRARY_PATH=:/home/sy1/.VimForCpp/vim/bundle/YCM.so/el7.x86_64
env[7]: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:
env[8]:MAIL=/var/spool/mail/sy1
env[9]:PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/sy1/.local/bin:/home/sy1/bin
env[10]:MYENV=aaaaaa
env[11]:PWD=/home/sy1/1_19
env[12]:LANG=en_US.utf8
env[13]:SHLVL=1
env[14]:HOME=/home/sy1
env[15]:LOGNAME=sy1
env[16]:LESSOPEN=||/usr/bin/lesspipe.sh %s
env[17]:PROMPT_COMMAND=history -a; history -a; printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
env[18]:HISTTIMEFORMAT=%F %T
env[19]:_=./Path
env[20]:OLDPWD=/home/sy1
子进程继承父进程的环境变量,因此环境变量是全局性的!
通过代码获取环境变量
通过第三方变量environ
获取环境变量,获取的结果与env参数是一样的。
#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;
}
environ是libc库中的变量,不包含在任何头文件中 ,需要先声明后使用。
通过系统调用获取环境变量
-
getenv()
根据环境变量名返回对应的值(以字符串形返回)。
在程序中通过getenv获取环境变量并使用允许你的程序在不同的系统上运行而不需要硬编码路径或其他配置信息。这使得你的程序更加灵活和可移植,因为它可以根据环境动态适应。下面是一个简单的例子:只有用户sy1才可以执行Path程序
[root@VM-16-11-centos 1_19]# cat Path.c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main() { char* user_value = getenv("USER"); if (strcmp(user_value, "sy1") == 0) { //执行代码 printf("haha!\n"); } else { printf("你没有权限运行!\n"); } return 0; } [root@VM-16-11-centos 1_19]# ./Path #当前用户是root,没有权限执行 你没有权限运行! [root@VM-16-11-centos 1_19]# su - sy1 #切换为用户sy1,USER环境变量为sy1 Last login: Fri Jan 19 19:08:43 CST 2024 on pts/0 [sy1@VM-16-11-centos ~]$ cd 1_19/ [sy1@VM-16-11-centos 1_19]$ ./Path #当前用户为sy1,可以执行 haha!