【Linux从入门到放弃】环境变量

🧑‍💻作者: @情话0.0
📝专栏:《Linux从入门到放弃》
👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢!

在这里插入图片描述

文章目录

  • 前言
  • 一、环境变量是什么?
    • 1.1 概念
    • 1.2 从Linux角度认识环境变量
    • 1.3 查看环境变量
    • 1.4 获取环境变量
      • 1.4.1 通过命令行第三个参数
      • 1.4.2 通过第三方变量environ
      • 1.4.3 通过函数获取
    • 1.5 环境变量概念再总结
    • 1.6 环境变量的数据从哪来?
  • 二、main函数的参数列表
    • 2.1 参数介绍
    • 2.2 命令行参数的含义
  • 三、进程优先级
    • 3.1 概念
    • 3.2 为什么有优先级呢?
    • 3.3 查看系统进程优先级 (`ps -l`)
    • 3.4 更改进程优先级
  • 总结


前言

  提到环境变量,大家应该都不会陌生,不管学习Java还是Phython都需要去安装环境变量,尤其是我自己在做深度学习时配置环境变量简直了,那叫一个惨,真的是莫名其妙不知道是哪里出的错,总之就是很难!那么今天的目的就是解释一下什么是环境变量。


一、环境变量是什么?

1.1 概念

  环境变量是在操作系统当中由系统在开机之后帮我们维护的一些系统运行时的动态参数。

1.2 从Linux角度认识环境变量

  环境变量因为所针对的场景不同,应用的软件不同而会有不同的种类。

  1. 我们在Linux中写的代码在编译之后形成的可执行程序为什么运行的时候要加上./呢?
  2. 可执行程序它是工具吗?是指令吗?比如我们可以执行指令file /user/bin/ls其实发现我们平时用的指令本质就是拿C写的可执行程序。当然我们自己写的可执行程序也可以通过这样的方式来查看。

那么这两种有什么区别呢? 答案是没有任何区别,只不过那些指令被纳入到了Linux基本指令的范畴中了。

  1. 我们可以从这样的一个角度出发,为什么系统的指令(可执行程序)不用加./,而运行我自己写的非得加上./呢?反过来说,我也想让我的程序不用加上./就可以运行该怎么做呢?

我们自己运行程序的方式其实是采用相对路径的方式来完成的,当然绝对路径的方式也是可以的。而之所以默认的指令可以不加./是因为在系统中存在一个环境变量,可以通过这个环境变量帮助我们在系统中特定路径下去搜索对应的命令。而这个环境变量是PATH,可以通过echo $PATH查看变量内容。

//我自己机器对应的环境变量
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zhuxu/.local/bin:/home/zhuxu/bin

系统的指令在执行时会在这个环境变量中一个个查找,找到了就直接执行,而我们对应的可执行程序对应的路径肯定不在里面,因此在执行时就得加上路径。
在这里插入图片描述
通过上图可以看到ls命令在/user/bin目录下,而这个就在PATH环境变量中(包含多个路径,以冒号作为分隔符),但是自己的可执行程序并不在其中。那我们将这个路径添加到环境变量中应该就可以直接执行了吧。
在这里插入图片描述
可以通过上面这条指令给环境变量中添加那条路径,再查看环境变量明显发现多了一条路径,而这就是我们自己写的可执行程序对应的路径。这样就可以不用加./而直接运行程序了。

  1. 除了上面的做法,那我们还可以直接将可执行程序添加到环境变量中的系统默认路径下——而这种方式就相当于Linux下的软件安装。当然不要了的话可以直接删除——卸载。

1.3 查看环境变量

env //很简单,这个命令就可以查看所有的环境变量

在这里插入图片描述
常见环境变量:

PATH : 指定命令的搜索路径
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash。

1.4 获取环境变量

  我们一般写main函数时都是不写参数的,但是人家其实是有参数的,而且还有三个参数,分别是:int argc、char *argv[]、char *envp[],前两个大家应该还挺熟悉,第三个参数被称为环境变量表。
  这个环境变量表是一个指针数组,每一个位置存放着地址数据,基本上指向一个个字符串,最后必须以NULL结尾。

1.4.1 通过命令行第三个参数

#include <stdio.h>
int main(int argc,char *argv[],char *envp[])
{
	int i=0;
	for(;envp[i];++i)
	{
		printf("envp[%d]:%s\n",i,envp[i]);
	}
	return 0;
}

1.4.2 通过第三方变量environ

environ是一个二级指针,和命令行的第三个参数是一样的,都指向那张环境变量表。
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。

#include <stdio.h>
#include <unistd.h> 
int main()
{
  extern char **environ;
  int i=0;
  for(;environ[i];++i)
  {
    printf("environ[%d]:%s\n",i,environ[i]);
  }
  return 0;
}

到这里我们就能明白在进程内部本身就有环境变量。然后呢?有什么用呢?我们是可以拿到一张环境变量表,难道我们要用某个环境变量的时候还得从这个表一个个去查找吗?那岂不是太挫了。

1.4.3 通过函数获取

//通过环境变量命来获取对应的环境变量
char *getenv(const char *name);
#include <stdio.h>
#include <stdlib.h>

int main()
{
	char *path=getenv("PATH");
	if(path==NULL) perror("getenv");
	else printf("PATH:%s\n",path);
	return 0;
}
  1. 当然可以写一个获取当前路径的方法,那最终出来的效果是和系统本身指令pwd是一样的。
  2. 如果你想写一个只允许你自己执行的进程,那么可以获取USER这个环境变量,只要它的用户和你设置的用户名不同那就不能够执行。

1.5 环境变量概念再总结

  1. 环境变量本质就是一张内存级的一张表,这张表由用户在登陆系统的时候,进行给特定用户形成属于自己的环境变量表。
  2. 环境变量中的每一个都有自己的用途:有的是进行身份认证的,有的是进行确认当前路径的,有的是进行路径查找的,而有的是进行动态查找的等等。
  3. 每一个环境变量都有自己特定的应用场景。
  4. 每一个元素都是K-V类型的,不同名字对应不同的内容。

1.6 环境变量的数据从哪来?

  它是一张内存级的表,那么内存中的数据在没有加载到内存之前是从哪来的呢?都是从系统的相关配置文件中读取进来的
  在家目录下,有这么两个文件: .bash_profile.bashrc,它们本质都是 shell 脚本,每次重新登陆的时候,系统都会重新读取配置文件,将配置文件中的脚本一执行从而形成对应的环境变量。
  我们在执行命令时都是bash去执行的,除了这个,它也支持命令行式的定义变量export myval=100,这就相当于在bash内部定义了myval和100的字符串。
  每当我们登陆了系统之后,操作系统就会创建shell进程,它的功能是读取命令和命令行的。当我们在命令行中设置了刚才那个变量为100,那么shell就会将该命令以字符串的形式读入其中,并且在shell内部会维护一张环境变量表,然后通过一个指针指向那个字符串,也就相当于把这个命令导进了环境变量中使之成为环境变量中的一员。要知道,所有的命令都是shell的子进程,所以当执行命令的时候shell就会将自己的表传给它的子进程。

这也间接说明了环境变量具有全局属性,它是可以被相关子进程继承下去的。

  那怎么证明呢?

  1. 先将该命令导入环境变量中:export hello="world"
  2. 查看环境变量是否导入成功。
    在这里插入图片描述
  3. 编写代码通过函数调用的方式看是否能获取到刚设置的环境变量。
int main()
{
  char *path=getenv("hello");
  if(path==NULL)
    perror("getenv");
  else printf("%s\n",path);
  return 0;
}

注:
命令行式的导入环境变量不加export的话同样也是可以通过命令行的方法将设置的对应变量打印出来,但是函数调用的方法是不行的,为什么呢?原因就是这种方法定义出来的变量属于本地变量,只在shell内部有效,不能被子进程继承。

二、main函数的参数列表

2.1 参数介绍

int main(int argc,char *argv[])
argv:一张表,指针数组,
argc:指针数组元素的个数。
int main(int argc,char *argv[])
{
	int i=0;
	for(;i<argc;++i)
	{
		printf("argv[%d]->%s\n",i,argv[i]);
	}
	return 0;
}

在这里插入图片描述

  1. 当我们在命令行中这样输入,在shell看来他就是一个字符串,那就以空格为分隔符拆成一个个子串,./myproc为可执行程序,后面的一个个子串为参数选项。而那张参数表分别指向这一个个子串,最后NULL结尾。
  2. 那谁制作的这张表呢?当然是bash,也就是在执行命令的时候就将这张表做好了,而我们写的这个进程(子进程)使用这张表。
  3. bash(父进程)创建出来了一个个参数,然后子进程使用。

2.2 命令行参数的含义

可以根据命令行的参数选项不同而表现出不同的功能。

看下面的代码:

void Usage(const char* name)
{
  	printf("\nUsage: %s -[a|b|c]\n\n",name);
  	exit(0);
}

int main(int argc,char *argv[])
{
  	if(argc!=2) Usage(argv[0]);
  
  	if(strcmp(argv[1],"-a")==0) printf("打印当前目录下的文件名\n");
  	else if(strcmp(argv[1],"-b")==0) printf("打印当前目录下的文件的详细信息\n");
  	else if(strcmp(argv[1],"-c")==0) printf("打印当前目录下的文件名(包含详细信息)\n");
  	else printf("其他功能,待开发\n");
}

代码功能:实现了一个必须按照正确命令行参数规范输入而执行打印效果的demo。
当命令行参数个数为两个时才进行打印,若不是,就会进入Usage函数,这个函数功能就是告诉你应该怎样去正确的输入命令行。

在这里插入图片描述

从上图可以看出,当没有按照规范输入就会给出应该输入的规范模板,当正确输入时就会根据参数选项的不同而表现出不同的功能。这也就和ls命令和不同的选项而表现出不同的功能输出。

三、进程优先级

3.1 概念

  优先级指的是CPU资源分配的先后顺序
  当然优先级高的进程首先获取到CPU资源并执行,就可以把那些不重要的进程安排在其他位置,让优先级高的进程先运行,这样可以大大改善系统的整体性能。

3.2 为什么有优先级呢?

  举个简单例子,在学校里,每到中午的时候我们都要去食堂买饭,往往伴随着排队买饭的现象,原因就是卖饭窗口少,学生人数多。而优先级的出现就在于CPU资源有限。
  正是因为CPU资源的有限,导致了众多进程需要竞争获取资源,必定会有先后顺序,进而会有优先级的出现让进程使用CPU资源有一定的先后顺序。

3.3 查看系统进程优先级 (ps -l)

在这里插入图片描述

PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :该进程的nice值,修正数据

  每个进程都有自己的PRI,而这个数字则代表着自己的执行优先级,也就是该程序被CPU执行的先后顺序,此值越小进程的优先级别越高,NI表示修正数据,这个东西是Linux操作系统独有的,在其它操作系统中是没有的。
  当然,一个进程最终的优先级不只是仅仅看PRI的大小,还有需要看Ni的值。PRI(new)=PRI(old)+NI
  NI值为负值的时候,那么该程序将会优先级数值将变小,即其优先级会变高,则其越快被执行。所以,在Linux下调整进程优先级就是调整进程NI值,NI其取值范围是-20至19,一共40个级别。

3.4 更改进程优先级

用top命令更改已存在进程的nice:top

进入top后按“r”–>输入进程PID–>输入nice值

当然除了这种还有其它方式,具体是那种在这里不多介绍,毕竟这个点不是很重要。有兴趣可以自己了解一下。


总结

此篇博客主要是对操作系统中的环境变量以及参数列表,进程优先级做了陈述,重点还是放在环境变量的理解上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/162185.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

torch.stack

看网上看多没讲的不是很明白&#xff0c;我来试试空间上的理解 # 假设是时间步T1的输出 T1 torch.tensor([[1, 2, 3],[4, 5, 6],[7, 8, 9]]) # 假设是时间步T2的输出 T2 torch.tensor([[10, 20, 30],[40, 50, 60],[70, 80, 90]])输出&#xff1a; print(torch.stack((T1,T2…

Spring Boot中配置文件生效位置

1. 配置文件位置 首先小伙伴们要明白&#xff0c;Spring Boot 默认加载的配置文件是 application.properties 或者 application.yaml&#xff0c;properties优先级高于yaml。默认的加载位置一共有五个&#xff0c;五个位置可以分为两类&#xff1a; 从 classpath 下加载&…

设计模式-行为型模式-责任链模式

一、什么是责任链模式 责任链模式是一种设计模式。在责任链模式里&#xff0c;很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递&#xff0c;直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求&…

【数据分享】2023年我国省市县三级的专精特新“小巨人”企业数量(Excel/Shp格式)

企业是经济活动的参与主体。一个城市的企业数量决定了这个城市的经济发展水平&#xff01;比如一个城市的金融企业较多&#xff0c;那这个城市的金融产业肯定比较发达&#xff1b;一个城市的制造业企业较多&#xff0c;那这个城市的制造业肯定比较发达。 之前我们给大家分享了…

【数据结构】10道经典面试题目带你玩转链表

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 一.移除链表元素 二.反转链表 三.链表的中间结点 四.链表中倒数第K个结点 五.合并两个有序链表 六.链表分割 七.链表的回文结构 八.相交链表 九.环形链表 一.移…

国内优质企业网盘推荐:满足您的文件存储与共享需求

企业网盘是主要用于企业工作过程中给的文件存储、共享以及协作。很多用户在挑选文件协作工具时更偏爱国内的工具&#xff0c;原因是使用上可能更贴合国人的使用习惯&#xff01; 那么现在国内做的比较好的企业网盘有什么&#xff1f; Zoho Workdrive企业网盘&#xff0c;ZOHO…

.NET 8 正式 GA 遥遥领先

.NET 8 一正式 已正式 GA。 微软称 .NET 8 提供了数以千计的性能、稳定性和安全性改进&#xff0c;以及平台和工具增强功能&#xff0c;有助于提高开发者的工作效率和创新速度。 比如 .NET 8 为 Android 和 WASM 引入了全新的 AOT 模式、改进 System.Text.Json&#xff0c;以…

谈谈如何写作(二)

序言 没有什么比一套好理论更有用了。——库尔特勒温 谈谈如何写作系列今天进入第二篇&#xff0c;第一篇请速戳&#xff1a;谈谈如何写作&#xff08;一&#xff09; 今天&#xff0c;博主从如何写报告讲起。 Q&#xff1a;如何写报告 如何写报告呢&#xff1f; 当每位盆友接到…

MAXScript实现简单的碰撞检测教程

在本教程中&#xff0c;我们将创建一个使轮子在地形上跟随的脚本。此脚本将没有任何UI。并且仅适用于特定对象。 因此&#xff0c;第一步是创建一个新的脚本。打开侦听器窗口&#xff0c;然后在文件菜单下选择“新建脚本…”。 我们首先需要创建与场景中的对象相对应的3个变量…

实战提升(六)

前言&#xff1a;Practice makes perfect&#xff01;今天实战Leetcode链表分割还有回文结构。今天的题全都来自于牛客网。 实战一&#xff1a; 思路&#xff1a;我们一这个链表为例&#xff0c;小于5的链表尾插到第一个链表&#xff0c;大于5的链表尾插到第二个链表&#xf…

【开源】基于Vue.js的开放实验室管理系统的设计和实现

项目编号&#xff1a; S 013 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S013&#xff0c;文末获取源码。} 项目编号&#xff1a;S013&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

vim指令

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握vim&#xff0c;并且能用vim敲出简单的代…

【计算机组成原理】知识点巩固 - 存储器概述

目录 1、存储器分类 1.1、按存储介质分类 1.2、按存取方式分类 1.3、按信息的可改写性分类 1.4、按信息的可保存性分类 1.5、按功能和存取速度分类 2、存储器技术指标 2.1、存储容量 2.2、存取速度 3、存储系统层次结构 4、主存的基本结构 5、主存中数据的存放 5…

麒麟 ZYJ 服务器软件适配 参考示例

一、zyj 环境简介 1. ZYJ 概述 国产化 SMZYJ 是由国家 BM 主管部门鉴定并批准生产使用的国内自主开发的 整机 JM 国标设备&#xff0c;设备采用了自主设备基础硬件&#xff08;飞腾、国科微等&#xff09;、安全硬 件自主固件&#xff08;昆仑等&#xff09;自主 SM 专用操作…

7、传统CV之高斯滤波

这一节在上一节均值滤波的基础上,再进阶一下,了解一下什么是高斯滤波。 首先,如上一节所说,均值滤波是利用一个窗口在图片上滑动,每次都计算窗口内能看到的像素的平均值,然后将平均值作为滤波的输出,从而可以起到平滑图像、去噪点的作用。 有没有发现,此时并没有特别…

栈的实现及OJ练习(c语言)

目录 前言 栈 栈的实现&#xff08;数组栈&#xff09; 初始化栈 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 检测栈是否为空 销毁栈 最终代码&#xff1a; 选择练习 栈的OJ题 前言 我们在之前已经学习了顺序表和链表的概念&#xff0c;它们有这样的优缺点&a…

4.2 Windows驱动开发:内核中进程线程与模块

内核进程线程和模块是操作系统内核中非常重要的概念。它们是操作系统的核心部分&#xff0c;用于管理系统资源和处理系统请求。在驱动安全开发中&#xff0c;理解内核进程线程和模块的概念对于编写安全的内核驱动程序至关重要。 内核进程是在操作系统内核中运行的程序。每个进…

键鼠自动化2.0展示

软件介绍&#xff1a;桌面键鼠自动化工具 Qtc 编写&#xff1a; 本软件采用Qt C编写&#xff0c;旨在提供高效、跨平台的桌面键鼠自动化解决方案。Qt C框架的选择确保了软件的稳定性、可靠性&#xff0c;并通过其图形用户界面实现了用户友好的操作体验。 鼠标移动与点击&#…

MySQL 的执行原理(一)

5.1 单表访问之索引合并 我们前边说过 MySQL 在一般情况下执行一个查询时最多只会用到单个二级 索引&#xff0c;但存在有特殊情况&#xff0c;在这些特殊情况下也可能在一个查询中使用到多个二 级索引&#xff0c;MySQL 中这种使用到多个索引来完成一次查询的执行方法称之为&…

物联网AI MicroPython学习之语法 SPI串行外设通信

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; SPI 介绍 模块功能: SPI串行外设驱动 接口说明 SPI - 构建SPI对象 函数原型&#xff1a;SPI(id, baudrate&#xff0c;polarity, phase&#xff0c;sck, mosi, miso)参数说明&#xff1a; 参数类型必选参…