在c/C++当中,根据不同程序的需要,我们需要为该程序定义某些变量int _data
,double _price
;
这些变量本质上就是一段内存空间,用来存储程序需要的值或数据;
而在OS中,OS本身在运行当中也需要一些必要的值或者数据,所以在OS当中也会存在一些变量用来存储这些所谓必要的值或者数据参数;
本质上来说环境变量(environment variables)一般是指操作系统中指定操作系统运行环境的一些参数;
一般常见的环境变量有:
PATH
HOME
SHELL
/bin/bash
;在Linux当中可以使用env
命令打印所有的环境变量;
查看环境变量一般的方式是利用echo
命令将环境变量进行打印;
语法:
echo $NAME
其中:
NAME
指环境变量名
echo
命令在Linux中的作用为:用于显示消息或输出其他命令的结果;
其中若是使用echo
打印环境变量时必须使用$
符,否则将会直接将环境变量名当作字符串进行打印;
$ echo PATH
PATH
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin
echo
:显示某个环境变量值;
export
:设置一个新的环境变量;
env
:显示所有环境变量;
unset
:清除环境变量;
set
:显示本地定义的shell变量和环境变量;
存在一个程序mytest
:
其主要的作用为打印hello world
;
std::cout << "hello world"<< std::endl ;
$ /usr/bin/ls
Makefile mytest test.cpp
$ ls
Makefile mytest test.cpp
$ ./mytest
hello world
$ mytest
-bash: mytest: command not found
已知ls
本身就是一个程序,且该程序存在于路径usr/bin/ls
;
在该程序中运行了两个程序:mytest
与ls
,分别为用户(我)创建的程序mytest
与OS中自带的命令程序ls
;
但是在使这两个程序运行时的方式并不同,在运行用户的程序时必须使用相对路径或者绝对路径从而运行程序,而在使用OS自身的程序时对路径的需求却可有可无;
很显然这个原因是因为:
本质上的原因是因为在OS当中,无论是运行什么程序都需要保证首先得找到这个程序(即拥有这个程序的路径)才能将该程序进行运行;
而例如ls
之类的这样的命令,OS默认是可以直接找到它的,因为这些命令的所在位置都位于环境变量PATH
当中;
使用 echo
打印环境变量$PATH
:
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin
从打印出来的结果中可以发现,PATH
环境变量以/.../..
作为路径,:
作为分隔符;
使用which
找到ls
命令所在路径:
which
命令将在PATH
环境变量中寻找某个指令的地址;
$ which ls
alias ls='ls --color=auto'
/usr/bin/ls
ls
的所在路径正是在PATH
环境变量当中;
当在Linux命令行上输入对应的命令时,OS将会在PATH
环境变量中寻找该命令的地址;
顺序为从左至右且以:
作分隔符;
/usr/local/bin
,/usr/bin
,/usr/local/sbin
…
若是想使自己的程序设置成类似于ls
命令;
可以使用两种方式:
将文件移至PATH
环境变量的任意路径当中:
由于PATH
环境变量中所存储的命令或者文件都是以路径的形式进行存储;
所以可以将需要的文件添加至PATH
环境变量中的任意路径;
但是实际上这种方式一般是不可取的:
虽然以这种方式可以达到预期的效果:使得自己的程序能像命令一样直接运行
但是对应的有很大的副作用;
由于PATH
环境变量内的文件是OS预先设置好的,由于这种操作在Linux当中相当于将自己写的命令安装至OS中;
所以如果贸然的将自己的程序添加至路径当中可能会出现污染命令池;
使用export
命令将程序加入PATH
环境变量:
语法:
export PATH=$PATH:程序路径
使用pwd
查看可执行程序所在路径以及使用echo
命令打印当前PATH
环境变量:
$ pwd
/home/_user/Begin/my_-linux/Pro23/Environment1201/T1201
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin
使用export
将路径加入到PATH
环境变量后再对PATH
环境变量进行打印:
export PATH=$PATH:/home/_user/Begin/my_-linux/Pro23/Environment1201/T1201 # 设置
$ echo $PATH # 打印
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin:/home/_user/Begin/my_-linux/Pro23/Environment1201/T1201
此时多了一个/home/_user/Begin/my_-linux/Pro23/Environment1201/T1201
的路径;
不带路径直接运行该程序:
$ mytest
hello world
同时使用which
也可以在$PATH
环境变量中找到该程序:
$ which mytest
~/Begin/my_-linux/Pro23/Environment1201/T1201/mytest
同时这种方式在测试设置$PATH
环境变量较为安全;
因为在不改配置文件的前提下只使用命令行的模式(类似于export
)的方式对环境变量进行修改时,修改效果只在当前对话当中;
当重新登陆该会话时环境变量将恢复:
$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin
HOME
环境变量即为指定用户的主工作目录(即用户登陆到Linux系统当中时的默认路径);
实际上不同的用户使用echo
对HOME
环境变量进行打印时所得到的结果是不同的:
#------_user用户下------
$ echo $HOME
/home/_user
#------root用户下------
# echo $HOME
/root
除了以命令行的形式echo $变量名
,env
获取环境变量以外也可以通过程序,即以代码的形式获取环境变量;
实际上在main
函数当中也有三个形参,分别为:
int argc
向main函数传递的参数个数;
char *argv[]
代表执行的程序名称和执行程序时输入的参数;
char *env[]
环境变量信息;
int main(int argc , char *argv[] , char *env[])
{;}
其中int argc
与char *argv[]
都为命令行参数;
在main()
函数的参数当中,其中int argc
与char *argv[]
均为命令行参数;
可以通过这两个参数实现程序在不同的指令下做到不同的运行结果;
存在一个程序(mytest):
#include
using namespace std;
int main(int argc , char *argv[] , char *env[])
{
for(int i = 0;i<argc;++i){
printf("argv[%d]:%s\n",i,argv[i]);
}
return 0;
}
运行结果:
$ ./mytest -a -b -c -d -e -f
argv[0]:./mytest
argv[1]:-a
argv[2]:-b
argv[3]:-c
argv[4]:-d
argv[5]:-e
argv[6]:-f
可根据该运行结果配合Linux中类似于ls -a
等命令进行联想;
该参数的类型为一个指针数组类型,一个数组内所存储的数据都为char*
的指针;
而这个形参即为启动该进程的进程(即这个进程的父进程)传给该进程的环境变量信息;
可以推断出这个指针数组内的char*
指针实际上为字符串,而启动该进程的进程将环境变量信息以字符串的形式传递给该进程;
可以使用一个程序进行证明 (以字符串的形式打印环境变量);
存在一个程序(mytest):
#include
using namespace std;
int main(int argc , char *argv[] , char *env[])
{
for(int i = 0;env[i];++i){
cout<<env[i]<<endl;
}
return 0;
}
/*
* env[]为指针数组;
* 遍历该数组并以字符串的形式打印出每个char*字符串;
*/
在Linux下环境变量一般是以字符串的形式利用指针数组进行存储,并以指针数组的形式将其传递给main
函数;
实际上在一个程序当中,main()
函数当中的char*env[]
中的环境变量信息来自于其父进程;
即也验证了这个形参即为启动该进程的进程(即这个进程的父进程)传给该进程的环境变量信息;
验证:
存在一个程序(mytest):
#include
using namespace std;
int main(int argc , char *argv[] , char *env[])
{
for(int i = 0;env[i];++i){
cout<<env[i]<<endl;
}
return 0;
}
可以使用该程序获取当前的所有环境变量;
通过该程序配合| grep
可以查看该程序所接收的众多环境变量中的部分环境变量;
设置临时环境变量:
在该对话中并不存在一个MYTEST
的环境变量;
所以如果运行该程序并配合| grep MYTEST
也将不会有对应的结果;
$ ./mytest | grep MYTEST
$
使用export
命令设置一个临时的环境变量,且该环境变量的值为hello_world
;
$ export MYTEST=hello_world
再次运行程序同时再次使用| grep MYTEST
搜索该环境变量:
当再次搜索该环境变量时则可以找到;
$ ./mytest | grep MYTEST
MYTEST=hello_world
由于根据该程序中所打印的环境变量都是由main()
函数的第三个参数char *env[]
进行打印的;
由此可以推断出该程序的环境变量是由其父进程所传递,对应的来说一个进程①在运行另一个进程②时,进程①会将自身的环境变量传给进程②;
同时也可以得出一个结论:
环境变量将从配置文件开始以多叉树的形式分发给每一个进程(父子进程间环境变量的传递),因此可以认为环境变量是具有全局属性的;
同时在Linux中除了该种方式可以获取环境变量以外,还拥有一个全局的环境变量char** environ
,且其对于获取环境变量所调用的方式与使用main()
函数的第三个参数char *env[]
所调用的方式相同;
示例:
#include
using namespace std;
int main(int argc , char *argv[] , char *env[]){
extern char **environ;
for(int i = 0;environ[i];++i){
cout<<environ[i]<<endl;
}
}
由于environ
并不包含与任何头文件,所以在使用该全局变量前必须使用extern
进行声明;
getenv()
函数是包含于
头文件中的一个函数;
该函数能够通过所给的环境变量(字符串)返回对应的环境变量数据;
其语法为:
char *getenv(const char *name);
示例:
#include
using namespace std;
int main(int argc , char *argv[] , char *env[])
{
cout<<getenv("PATH")<<endl;
return 0;
}
调用:
$ ./mytest
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/_user/.local/bin:/home/_user/bin
通常来说大部分情况使用该方式获取对应的环境变量的所使用的频率要高于上面的两种;
其中最主要的原因是若是使用上面的两种方式获取环境变量则将会有大量的环境变量以字符串的形式进行展现,需要使用者进行二次甄别;
在上文中所提到的都为环境变量;
而在Linux中不仅可以定义环境变量还可以定义全局变量;
环境变量的定义:
export var_name=_value
示例:
$ export Test1=hello_world # 设置环境变量
$ echo $Test1 # 使用echo打印变量
hello_world
$ env | grep Test1 # 可以使用env显示所有环境变量,配合grep显示出对应的环境变量
Test1=hello_world
局部变量的定义:
var_name=_value
示例:
$ Test2=HELLO_WORLD # 设置环境变量
$ echo $Test2 # 使用echo打印变量
HELLO_WORLD
$ env | grep Test2 # 可以使用env显示所有环境变量,配合grep显示出对应的环境变量
$ # 无结果显示
在Linux当中可以使用set
显示所有的变量 (包括局部变量与环境变量);
$ set | grep Test1
Test1=hello_world
$ set | grep Test2
Test2=HELLO_WORLD