【Linux】环境变量和进程优先级
目录
环境变量 什么是环境变量
平时在使用Linux的时候,总会使用ls、pwd这类的命令,我们也都知道这些命令也是C语言写的,但是为什么我们自己写的可执行程序需要加上./才能运行?
这是因为一些在操作系统中用来指定操作系统运行环境的一些参数已经被存储到了环境变量表中。
这些特定的人在特定的场景中被使用的变量就叫环境变量。
我们可以通过env来查看整张环境变量表。
env
其中我们可以看到
PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
USER : 当前用户名
之后可以使用echo + $ + 环境变量名,查看变量的内容。
echo $USER //这里查看用户名这个环境变量
这里的$可以理解成使用指针时的*,因为若直接使用echo打印,则会输出输入的字符串。
也可以使用set查看本地变量和环境变量,且内容相较于环境变量多了许多。
又绕回一开始的问题,我们若想直接用文件名运行程序该怎么办呢?其中的奥秘就在这个PATH之中。
看这一串路径是否有些眼熟?我们平时使用的命令就存在这些路径下。
PATH中存的便是指定命令的搜索路径,因此若想直接用文件名运行程序,就需要让操作系统能够找到我们这个程序。
现有两种方法能够实现这个操作,其一便是将我们想要直接运行的文件直接拷贝到当前PATH的路径下。
其二则是将目标文件所在的路径加入到PATH路径下。
我们可以使用定义或修改环境变量。
export 环境变量名=变量中的内容
像这样我们便定义了一个环境变量,并且能够在环境变量表之中找到。
有了这个命令那么我们就能够将我们文件的路径加入到PATH之中了,但是千万不能直接像这样使用。
export PATH=/home/Alpaca/linux-code-library/text.4.18/environ (文件所在路径)
否则便会像如上这样,我们甚至无法找到系统自带的命令,但是确实是能够直接运行自己的程序。
若真的将自己的PATH整个改掉的话,不要慌张,重新连接一次服务器即可。
实际上需要这样写,就能将我们当前路径追加到PATH之中。
export PATH=$PATH:/home/Alpaca/linux-code-library/text.4.18/environ (文件所在路径)
如此我们便能够直接使用文件名来运行自己的代码了。
系统结构
虽然我们成功将我们当前的路径插入到了环境变量之中,但是只要我们关闭连接,再次打开后便会发现,我们的环境变量又恢复了原样。
因为我们的环境变量就存在环境变量表中,所以每次我们添加新的环境变量就相当于往这个表中插入数据。
而环境变量表本质就是内存级的一张表,这张表在用户登录系统的时候,系统便会给用户生成一张属于自己的环境变量表。
那环境变量所对应的数据都是从哪来的呢?我们可以看看/etc路径下的文件,便能观察到一系列环境变量是如何配置的。
而系统也正是执行这些特定的配置文件,进而配置当前用户的环境变量表。
正因为每个用户的环境变量都是独有一份,因此可以通过对用户名环境变量的检测来进行权限的限制。不仅如此,环境变量还可以被相关的子进程继承下去。
系统接口
系统给我们提供了一个接口(( ))供我们访问环境变量。根据man手册我们可以知道,我们需要给这个函数一个变量名,之后它便会在环境变量表之中进行查找。找到便返回指向目标内容的指针,反之则返回空指针。
我们便很容易写出这样的代码。
#include
#include
#include
#include
int main()
{
char* p = getenv("PWD");
std::cout<
之后我们将程序运行便发现,实际打印出来与PWD环境变量的内容一模一样。
本质上调用代码使其运行的就是bash,因而二者本身就是父子进程之间的关系,bash的环境变量能在子进程之中存在,也恰好证明了环境变量能够被相关子进程继承的这一结论。
不仅如此,还可以直接使用外部环境变量表的指针进行访问。
#include
#include
#include
#include
int main()
{
extern char** environ; //声明外部变量
for(int i = 0;environ[i];i++) //直到内容为空结束打印
{
printf("environ[%d]: %s\n",i,environ[i]);
}
return 0;
}
这样便可以打印出一张环境变量表。
深度解析
在Linux中不仅有环境变量,还有另一种变量叫做本地变量,定义环境变量时不加定义的便是本地变量。
但本地变量与环境变量不同的地方在于,其无法被子进程继承。因此我们在代码中是无法访问到本地变量的。
、
之后我们不再需要这个变量后可以使用unset将其删除。
命令行参数
平时我们都在使用main函数,但你知道main函数也有参数吗?其实main函数中最多能有三个参数。
int main(int argc, char *argv[], char *envp[])
{
return 0;
}
其中envp就是环境变量表, 我们直接打印便能够得到完整的环境变量表。
int main(int argc, char *argv[], char *envp[])
{
for(int i = 0;envp[i];i++)
{
std::cout<
重点在于argc和argv,不知道各位有没有想过: 为什么我们在使用命令的时候还能够加上选项?
在上面我们已经知道,使用命令本质上是运行一个可执行程序。那么后面跟上的选项又该如何理解呢?
由于argv也是一个指针数组我们不妨用以下代码将argv的内容打印出来看看。
int main(int argc, char *argv[], char *envp[])
{
for(int i = 0;argv[i];i++)
{
std::cout<
可以看出,命令的选项以字符串的形式传给了参数,因此有了不同的参数。
因此我们也可以根据运行时所带选项的不同,使程序执行不同的任务。
#include
#include
#include
#include
#include
int main(int argc, char *argv[], char *envp[])
{
if (argc == 1) //没有参数的情况
{
std::cout << "------------------" << std::endl;
printf("无任务执行,已退出\n");
std::cout << "------------------" << std::endl;
exit(0);
}
if (argc != 2) //参数过多的情况
{
std::cout << "------------------" << std::endl;
std::cout << "输入样例不合法" << std::endl;
std::cout << "------------------" << std::endl;
exit(2);
}
// 判断参数
if (strcmp(argv[1], "-a") == 0)
{
std::cout << "------------" << std::endl;
std::cout << "执行A任务" << std::endl;
std::cout << "------------" << std::endl;
}
else if (strcmp(argv[1], "-b") == 0)
{
std::cout << "------------" << std::endl;
std::cout << "执行B任务" << std::endl;
std::cout << "------------" << std::endl;
}
else if (strcmp(argv[1], "-c") == 0)
{
std::cout << "------------" << std::endl;
std::cout << "执行C任务" << std::endl;
std::cout << "------------" << std::endl;
}
else
{
std::cout << "无目标指令" << std::endl;
}
return 0;
}
根据传入参数的不同,从而进行不同的任务。
进程优先级
我们在以前学习过权限的相关内容,而权限与优先级的本质区别在于:
为什么有优先级?
cpu资源有限,当资源不足时根据优先级进行分配,保证先执行最重要的程序。
优先级查看
通过ps -l我们可以查看进程的优先级。
ps -l
其中UID代表的是用户,系统通过UID识别用户,但有一个专属的字符串与UID对应,供用户使用。
而表示优先级的是PRI,PRI越小进程优先级别就越高。
NI为修正数据,范围为[-20,19],一般来说不直接更改PRI而是通过修改NI从而达到修改优先级的效果。
优先级修改
如此便完成了修改。NI的修改值如果超出了范围,则会修改成范围最贴近的那个值。
值得注意的一点是:PRI(new) = PRI(old)+NI。
其中的PRI(old),每次都为80,即更改NI时刻关系着PRI的大小
进程间的概念
好了,今天环境变量和进程优先级的讲解到这里就结束了,如果这篇文章对你有用的话还请留下你的三连加关注。