1.命令行参数
在认识环境变量之前,先认识下命令行参数。Linux下各种指令有各种参数,指令都有一个main
函数,通过命令行参数传入main
函数。比如ls -a -l
中,把a,l
这两个参数传递给ls
这个程序中,以达到通过对应参数来指定程序执行结果的目的。
同样,可以自己写一个程序更好地进行理解,main
函数默认有很多参数,其中前两个是int argc, char* argv[]
。
c
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
通过执行程序并传递命令行参数后,进行命令行参数打印,可以看到命令行参数通过空格区分存放到argv
指针数组中。
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess -a
./myprocess
-a
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess -a -b
./myprocess
-a
-b
这样就可以通过命令行参数来实现同一程序的不同功能。
c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if (argc != 4)
{
printf("Usage:\n\t%s -[add|sub|mul|div] x y\n\n", argv[0]);
return 1;
}
int x = atoi(argv[2]);
int y = atoi(argv[3]);
if (strcmp(argv[1], "-add") == 0)
{
printf("%d+%d=%d\n", x, y, x+y);
}
else if (strcmp(argv[1], "-sub") == 0)
{
printf("%d-%d=%d\n", x, y, x-y);
}
else if (strcmp(argv[1], "-mul") == 0)
{
printf("%d*%d=%d\n", x, y, x*y);
}
else if (strcmp(argv[1], "-div") == 0)
{
printf("%d/%d=%d\n", x, y, x/y);
}
else
{
printf("unknown!\n");
}
return 0;
}
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess -add 1 2
1+2=3
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess -mul 3 4
3*4=12
命令行参数存放在main
函数第二个参数中,而环境变量存放在第三个参数env
中,该参数也是指针数组。
int main(int argc, char *argv[], char *env[])
也就是说,程序执行时,不仅会接收命令行参数表,也会接收一个环境变量表,这个环境变量表的结构与命令行参数表是一致的。
2.什么是环境变量
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数。
在编写C/C++的代码时,会引入一些库(例如iostream
),以供代码链接。但是在链接的时候,从来不知道所链接的动态链接库在哪里,同样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
环境变量 是一堆变量,是系统内置具有特殊用途的变量,变量的本质就是开辟空间存放数据。操作系统中bash
也是用C
写的,在运行中可以开辟空间申请变量,这里的环境变量就是bash
程序中的变量,以便bash
运行时进行一些操作(例如运行编译程序进行链接动态链接库)。
一般常见的环境变量有:
PATH
: 指定命令的搜索路径
HOME
: 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL
: 当前Shell,它的值通常是/bin/bash
Linux中通过echo $NAME
指令来查看指定环境变量的内容,这里的NAME
是指环境变量名,前必须有$
。
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning# echo $HOME
/root
root@hcss-ecs-e6eb:~/learning/Linux-learning# echo $SHELL
/bin/bash
root@hcss-ecs-e6eb:~/learning/Linux-learning# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
同时可以通过env
指令打印所有的环境变量
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning# env
SHELL=/bin/bash
HISTSIZE=1000
HISTTIMEFORMAT=%F %T root
PWD=/root/learning/Linux-learning
LOGNAME=root
XDG_SESSION_TYPE=tty
MOTD_SHOWN=pam
HOME=/root
LANG=en_US.UTF-8
...
其余和环境变量有关的指令
echo
: 显示某个环境变量值
export
: 设置一个新的环境变量
unset
: 清除环境变量
set
: 显示本地定义的shell变量和环境变量
PATH 环境变量
当执行自己写的程序时,需要在前面添加./
才能执行,但是在执行ls
程序时,则不需要。
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ls
makefile myprocess myprocess.c
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# myprocess
myprocess: command not found
本质原因是 :在操作系统中,运行程序需要先找到该程序的路径,ls
这样的命令,Linux中可以默认找到,因为这些命令的所在位置都处于环境变量PATH
中。而自己写的程序,只有通过./
系统才能知道该程序是在当前路径中的。
若想要自己的程序不需要./
就可以直接执行,有两种方法,一种是直接将该程序放置PATH
环境变量对应的路径中,但是不推荐,这样会污染命令池。
还有一种方法是通过export
命令将指定程序路径添加至PATH
环境变量中。
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# export PATH=$PATH:~/learning/Linux-learning/Process/
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/root/learning/Linux-learning/Process/
root@hcss-ecs-e6eb:~/learning/root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# myprocess -add 1 2
1+2=3
可以看到,export
命令后,PATH
新增了我需要添加程序的所在路径,同时直接myprocess
也成功了。
需要注意的是,使用export
而不修改配置文件(该文件在家目录.bashrc
中),只会在当前运行的bash
中起到作用,当窗口关闭重新运行一个新的bash
进程,由于默认配置文件没有被修改,新的进程中的环境变量不会被修改。
3.获取环境变量
通过代码获取环境变量
- 利用
mian
函数的第三个参数char *env[]
获取环境变量
c
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
// env指针数组以null为结尾,当 环境变量全部读取完毕循环会结束
for (int i = 0; env[i]; i++)
{
printf("%s\n", env[i]);
}
return 0;
}
- 通过第三方变量
environ
获取
c
#include<stdio.h>
int main()
{
extern char** environ;
for (int i = 0; environ[i]; i++)
{
printf("%s\n", environ[i]);
}
return 0;
}
通过系统调用获取环境变量
getenv()
函数是包含于<stdlib.h>
头文件中的一个函数,该函数可以通过所给环境变量名返回环境变量内容。
c
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%s\n", getenv("PATH"));
return 0;
}
通常情况下,更多使用系统调用来查看环境变量内容,该函数可以查看指定某一个环境变量的内容。
4.环境变量的全局属性
实际上,一个程序的main
函数中的char *env[]
中的环境变量信息来自其父进程。
当父进程创建一个子进程,会将其自身的环境变量信息作为参数传递给子进程。
还是这个程序,运行后想查看是否有名为MYTEST
的环境变量信息,此时肯定是没有的。
c
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
for (int i = 0; env[i]; i++)
{
printf("%s\n", env[i]);
}
return 0;
}
但在bash
使用export
命令添加环境变量,再进行检索,会显示该环境变量。由于myprocess
是bash
的子进程,其继承了bash
的环境变量表。
shell
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess | grep MYTEST
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# export MYTEST=test
root@hcss-ecs-e6eb:~/learning/Linux-learning/Process# ./myprocess | grep MYTEST
MYTEST=test
由于变量的存在,shell
也成为一门语言,在后续自己编写一个shell
程序,环境变量至关重要。