目录
基本概念
查看环境变量方法
环境变量的导入
【永久路径】
windows环境变量
常见的环境变量
环境变量相关的命令
命令行参数
通过代码如何获取环境变量
环境变量具有全局属性
基本概念
- 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
- 我们在写C/C++代码的时候,在链接的时候,从来不知道我们所链接的动态/静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
- 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。
当写下面这个程序,并用make工具进行编译
[wjy@VM-24-9-centos 407test]$ cat myproc.c
#include <stdio.h>
#include <unistd.h>int main()
{int cnt=5;while(cnt){sleep(1);printf("I am a cmd -> process!\n");cnt--;}return 0;
}[wjy@VM-24-9-centos 407test]$ cat makefile
myproc:myproc.cgcc -o $@ $^ -std=c99
PHONY:
clean:rm -f myproc
make编译之后,生成可执行文件
[wjy@VM-24-9-centos 407test]$ ll
total 20
-rw-rw-r-- 1 wjy wjy 68 Apr 7 16:18 makefile
-rwxrwxr-x 1 wjy wjy 8408 Apr 7 16:20 myproc
-rw-rw-r-- 1 wjy wjy 167 Apr 7 16:20 myproc.c
[wjy@VM-24-9-centos 407test]$ ./myproc
I am a cmd -> process!
I am a cmd -> process!
I am a cmd -> process!
I am a cmd -> process!
I am a cmd -> process!
在我们用make工具写一个命令执行文件时候,会生成一个文件,这个文件就是用来执行源程序文件的编译文件,然后想要链接将程序结果打印在屏幕上,我们会输入“./xxx”命令。这些命令,程序,工具等等都是一个可执行文件。那么在运行的时候,为何要“./”呢?
我们知道./就是当前路径,当输入./后,就会帮系统确认对应的程序在哪里。那么为何系统的命令不用带路径呢?
通常执行一个程序需要找到对应路径下的文件,但是系统的命令可以不带路径,系统的命令可以自己找到这条命令,那么系统是怎样找到这条命令呢?
这时因为环境变量--PATH的原因。
查看环境变量方法
echo $PATH//PATH:环境变量名称,还有很多环境变量
获取./对应的路径,也就是环境变量,需要输入下面命令。但是需要主义的是,PATH前面要加$符号,PATH就像(但不是)一个指针,指针解引用之后才能取到里面内容,所以PATH前面要加一个$符号。
这里所有路径都用一个冒号作为分隔符,分割出了多条路径。所以系统想通过PATH找到路径,它的查找规则就是,在PATH当中先找第一个,找不到就找第二个路径,找不到再找下一个,如果找到了,后续就不再找了,那么系统将它的可执行程序跑起来。
但是我们并不推荐去自己自定义环境变量,因为拷进去之后会污染系统的命令池,时间长了可能会发现为什么这条语句会有一个打印语句。
当我们要在系统中安装一个软件,安装的过程就是将软件的路径拷贝到特定的系统命令路径下,完成安装,所以安装的过程就是拷贝的过程。
所以PATH就是搜索路径,系统能够找到命令,就是通过PATH找到环境变量
[wjy@VM-24-9-centos 407test]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/wjy/.local/bin:/home/wjy/bin
环境变量的导入
如果就想用环境变量执行命令,该怎么把环境变量导入系统路径呢?
- export 导入
- 要进行环境变量的重新设置
- 设不能把当前路径直接给拷进来,当我们把当前路径直接拷到系统路径下,拷贝完再次查看路径发现,系统路径只剩下刚才设置的路径了,以前系统配置好的路径都没有了,输入系统默认路径命令,如ls,touch+文件,都没有了
但是我们并不用担心路径被破坏,这只是内存级别的路径,我们只要重启linux系统,路径就会恢复过来。
[wjy@VM-24-9-centos 407test]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/wjy/.local/bin:/home/wjy/bin
[wjy@VM-24-9-centos 407test]$ pwd
/home/wjy/LinuxTest/407test
[wjy@VM-24-9-centos 407test]$ export PATH=/home/wjy/LinuxTest/407test
[wjy@VM-24-9-centos 407test]$ echo $PATH
/home/wjy/LinuxTest/407test//路径全没了
[wjy@VM-24-9-centos 407test]$ ls
-bash: ls: command not found
[wjy@VM-24-9-centos 407test]$ pwd
/home/wjy/LinuxTest/407test
[wjy@VM-24-9-centos 407test]$ touch file.txt
-bash: touch: command not found
所以为了不让系统路径被修改,需要这样的格式【export PATH=$PATH:...】,发现拷贝成功。这样上面的程序不用./也可以运行成功。
【永久路径】
如果想要把自定义路径变为和系统一样的永久路径,那么需要修改bash_profile文件,这个文件会在登陆时自动执行,如果想要修改,直接把路径拷贝在后面
[wjy@VM-24-9-centos 407test]$ vim ~/.bash_profile
windows环境变量
同样windows系统中也有环境变量的东西,它是通过:我的电脑->属性->高级系统设置->环境变量,就可以看到path。这就是我自己执行程序时对应的路径。
在windows中也有像linux系统一样的黑框框,只输入一个calc,就能把计算器调出来,这是为什么呢?就是因为环境变量的路径,系统直接找到这个路径,直接就能把程序调出来。
常见的环境变量
- PATH:指定命令的搜索路径
- HOME:指定用户的主工作目录(即用户登录到Linux系统中时的默认目录),每个用户的home环境变量都是不一样的
- SHELL:当前Shell。它的值通常是/bin/bash,
[wjy@VM-24-9-centos ~]$ echo $HOME
/home/wjy
[wjy@VM-24-9-centos ~]$ echo $SHELL
/bin/bash
env命令可以看到系统中所有的环境变量。它可以查看所有命令的环境变量。比如说查看当前机器是什么名字,用hostname变量。
[wjy@VM-24-9-centos ~]$ echo $SHELL
/bin/bash
系统上还存在一种变量,是与本次登录(session)有关的变量,只在本次登录有效--叫做本地变量。
所以系统当中存在大量的属性变量来保存维护系统当中运行的的状态信息,每一种环境变量都有不同的职责,有的是用来搜索路径,有的用来查命令,有的确认主机名等等。这些信息都是在系统当中维护起来,就叫做环境变量。
语言上面定义变量本质是在内存中开辟空间,OS开辟空间能力非常强大,环境变量本质是OS在内存/磁盘文件中开辟的空间,用来保存系统相关的数据。
环境变量相关的命令
- echo:显示某个环境变量的值
- export:设置一个新的环境变量
- env:显示所有的环境变量
- unset:清除环境变量
- set:显示本地定义的shell环境和环境变量
环境变量是全局的,当定义一个本地变量,用set可以显示出来,但是env并不显示。export可以将本地变量变成环境变量,unset可以取消刚才设置的本地变量。
命令行参数
我们知道,main也可以带参数,这里argc代表数组元素个数,argv是一个指针数组,数组中每个元素都是字符串。
举个例子,写一个命令行参数函数,argc是数组元素个数,所以写一个for循环,来遍历这个指针数组中的每一个元素。
int main(int argc,char *argv[])
{for(int i=0;i<argc;i++){printf("argv[%d] -> %s\n",i,argv[i]);}
}
我们用make文件命令来执行这段程序,因为我们只输入了./myproc命令,所以数组个数只有一个,下标从0开始,它的字符串就是我们所打的命令。如果在命令后面再加几个命令,那么数组个数也会变多,命令之间是用空格区分开来,用一个空格隔开,就多一个数组,指针数组中最后一个元素是NULL。所以argc决定有几个命令行字符串
【那么为什么要有命令行参数?】
linux命令中有很多命令加选项,他们是怎样通过附加命令的方式来判断做什么操作呢?
#include <stdio.h>
#include <string.h>int main(int argc,char *argv[])
{if(argc!=2)//如果数组元素个数不是2,也就是为1的时候,提示需要输入选项{printf("Usage:%s -[a|h]\n",argv[0]);return 1;}//输入选项的结果if(strcmp(argv[1],"-h")==0){printf("hello optionH\n");}else if(strcmp(argv[1],"-a")==0){printf("hello optionA\n");}else {printf("hello world!\n");}
}
通过上面的代码,执行结果,发现当只输入./myproc一个命令,就会提示你输入要选的选项,也就是说,这个命令必须要输入选项。输入对应的选项就有结果。
所以指令有很多选项,用来完成同一个命令的不同功能,选项底层使用的就是我们命令行参数!
通过代码如何获取环境变量
上面我们了解,通过echo $env,可将环境变量都显示出来。那么我们也可以使用环境变量作为命令行参数变量,并进行遍历,将所有环境变量打印出来。
int main(int argc,char* argv[],char* env[])
{for(int i=0;env[i];i++){printf("%s\n",env[i]);}return 0;
}
[wjy@VM-24-9-centos 407test]$ ./myproc
XDG_SESSION_ID=139860
HOSTNAME=VM-24-9-centos
TERM=xterm
SHELL=/bin/bash
HISTSIZE=3000
SSH_CLIENT=111.43.18.174 52411 22
SSH_TTY=/dev/pts/2
USER=wjy
...//下面就不显示出来
第二种方法就是不带参数,运用一个二级指针,因为数组中存储的是char类型字符串,数组的每一个元素用char*指向字符串的首元素。那么用一个二级指针指向数组,对二级指针++,就得到下一个元素,对二级指针解引用得到数组中的每一个元素。
环境变量是可以传到程序里面的。
int main()
{extern char **environ;for(int i=0;environ[i];i++){printf("%d->%s\n",i,environ[i]);}
}[wjy@VM-24-9-centos 407test]$ ./myproc
但是前两种方法并不推荐使用,只是想演示可以用这两种方法做到获取环境变量。
那么第三种方法,是用库函数getenv来获取环境变量。
#include <stdlib.h>//getenv函数需要包含头文件stdlib
int main()
{printf("PATH:%s\n",getenv("PATH"));printf("HOME:%s\n",getenv("HOME"));printf("SHELL:%s\n",getenv("PATH"));return 0;
}
环境变量具有全局属性
当我们写一个程序,发现无论这个程序执行多少次,他们的进程号在改变,但是父进程都是同一个,因为他们的父进程都是bash
#include <unistd.h>
int main()
{printf("I am a process pid:%d,ppid:%d\n",getpid(),getppid());
}
我们知道环境变量可以被子进程继承,因为子进程的环境变量是系统给的,也可以理解成是父进程通过fork()创建子进程给的,父进程的环境变量是bash给的,bash的环境变量是从系统的配置文件读取出来的,类似于读文件。那么本地变量也可以被子进程继承吗?
我们输入一个环境变量,并让他在env下输出,发现程序崩溃。
[wjy@VM-24-9-centos 407test]$ my_env_string="aaa"
[wjy@VM-24-9-centos 407test]$ echo $my_env_string
aaa[wjy@VM-24-9-centos 407test]$ vim myproc.c
int main()
{printf("my_env_string:%s\n",getenv("my_env_string"));return 0;
}[wjy@VM-24-9-centos 407test]$ make
gcc -o myproc myproc.c -std=c99
[wjy@VM-24-9-centos 407test]$ ./myproc
my_env_string:(null)
但是我们通过导入环境变量,将本地变量my_env_string导入父进程的环境变量列表bash中,本地变量才算导入成功。
本地变量不能被子进程继承,如果将本地变量导入到可以被继承的全局环境变量bash中,那么本地变量也将继承成功。
环境变量是可以被子进程继承的。环境变量具有全局属性,本质是环境变量可以被子进程继承下去。
[wjy@VM-24-9-centos 407test]$ export my_env_string
[wjy@VM-24-9-centos 407test]$ env | grep my_env_string
my_env_string=aaa
[wjy@VM-24-9-centos 407test]$ ./myproc
my_env_string:aaa