【Linux】14.Linux进程概念(3)

ops/2025/1/22 18:07:29/

文章目录

  • 1. 其他概念
  • 2. 环境变量
    • 2.1 基本概念
    • 2.2 常见环境变量
    • 2.3 查看环境变量方法
    • 2.4 测试PATH
    • 2.5 测试HOME
    • 2.6 和环境变量相关的命令
    • 2.7 环境变量的组织方式
    • 2.8 通过代码如何获取环境变量
    • 2.9 通过系统调用获取或设置环境变量
    • 2.10 环境变量通常是具有全局属性的
    • 2.11 常规命令和内建命令
    • 2.12 实验
    • 2.13 本地变量和环境变量的主要区别


1. 其他概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

  1. 函数的返回值是怎么被外部拿到的呢?

    通过寄存器

  2. 系统如何得知我们的进程当前执行到哪行代码的呢?

    程序计数器pc/eip:记录当前进程正在执行指令的下一行指令的地址。

  3. 寄存器很多,扮演什么角色?

    提高效率,进程的高频数据会放入寄存器中。

  4. CPU内的寄存器里面保存的是什么数据?

    进程相关的数据,里面保存的是进程的临时数据,是当前进程的上下文数据。

    进程在从 CPU离开的时候,要将自己的上下文的数据保存好,甚至带走。保存到目的是为了未来恢复进程。

  5. 进程被切换的时候:

    保存上下文数据

    恢复上下文数据


2. 环境变量

2.1 基本概念

  • 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。

  • 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性

  • 环境变量是系统提供的一组name=value形式的变量,不同的环境变量有不同的用户,通常具有全局属性。


2.2 常见环境变量

  • PATH : 指定命令的搜索路径

  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)

  • SHELL : 当前Shell,它的值通常是/bin/bash。


2.3 查看环境变量方法

echo $NAME //NAME:你的环境变量名称


2.4 测试PATH

  1. 首先创建并编译hello.c
#include <stdio.h>int main()
{printf("hello world!\n");return 0;
}
gcc hello.c -o hello
  1. 执行对比:
./hello       # 使用相对路径执行
hello         # 直接执行会提示找不到命令
  1. 系统命令可以直接执行的原因:
  • 系统会在PATH环境变量指定的目录中查找可执行文件
  • 常用命令通常位于 /bin/usr/bin 等已经包含在PATH中的目录
  • 而当前目录 . 默认不在PATH中,所以需要指明路径
  1. 将程序路径添加到PATH
export PATH=$PATH:$(pwd)    # pwd获取当前目录的完整路径
  1. 添加PATH后:
hello    # 现在可以直接执行了,系统会在PATH中查找

2.5 测试HOME

root和普通用户,分别执行 echo $HOME ,对比差异

. 执行 cd ~; pwd ,对应 ~HOME 的关系

  1. 用不同用户执行echo $HOME
# 普通用户执行
echo $HOME
/home/用户名# 切换到root用户执行
su root
echo $HOME
/root
  1. 执行cd ~pwd
cd ~ # 切换到主目录
pwd
# 普通用户会显示: /home/用户名
# root用户会显示: /root

~HOME的关系:

  • ~HOME环境变量的简写符号
  • ~ 会自动展开为当前用户的家目录路径
  • HOME环境变量存储了用户的家目录路径
  • 在命令行中,~$HOME是等价的,例如:
    cd ~         # 等价于 cd $HOME
    ls ~/.bashrc # 等价于 ls $HOME/.bashrc
    

主要区别:

  • 普通用户的家目录在/home/用户名
  • root用户的家目录在/root
  • 每个用户都有自己独立的HOME路径

2.6 和环境变量相关的命令

  1. echo: 显示某个环境变量值

  2. export: 设置一个新的环境变量

  3. env: 显示所有环境变量

  4. unset: 清除环境变量

  5. set: 显示本地定义的shell变量和环境变量


2.7 环境变量的组织方式

fd0e8046c658d62eb097b04656d9aca0

每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串


2.8 通过代码如何获取环境变量

命令行第三个参数

#include <stdio.h>int main(int argc, char *argv[], char *env[])
{int i = 0;for(; env[i]; i++){printf("%s\n", env[i]);}return 0;
}
  1. 通过main函数第三个参数获取:
int main(int argc, char *argv[], char *env[])
  • envmain函数的第三个参数
  • 它是一个指向字符串数组的指针
  • 数组以NULL结尾
  • 每个字符串的格式为"NAME=VALUE"

通过第三方变量environ获取

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

libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。

  1. 通过environ变量获取:
extern char **environ;
  • environ是一个全局变量
  • 它指向同样的环境变量表
  • 需要用extern声明是因为:
    • environ变量定义在C运行时库(libc)中
    • 它不在任何标准头文件中声明
    • extern告诉编译器这个变量在其他地方定义
    • 链接器会在运行时库中找到这个符号

2.9 通过系统调用获取或设置环境变量

putenv , 后面讲解

getenv , 本次讲解

#include <stdio.h>
#include <stdlib.h>int main()
{printf("%s\n", getenv("PATH"));return 0;
}

常用getenvputenv函数来访问特定的环境变量。

代码解析:

  • getenv()是标准库stdlib.h中的函数
  • 参数是要查询的环境变量名称(字符串)
  • 返回值是该环境变量的值(字符串),若变量不存在则返回NULL
  • 此例中获取PATH环境变量的值并打印

2.10 环境变量通常是具有全局属性的

环境变量通常具有全局属性,可以被子进程继承下去

#include <stdio.h>
#include <stdlib.h>int main()
{char * env = getenv("MYENV");if(env){printf("%s\n", env);}return 0;
}

直接查看,发现没有结果,说明该环境变量根本不存在

导出环境变量

export MYENV="hello world"

再次运行程序,发现结果有了!说明:环境变量是可以被子进程继承下去的!想想为什么?


  1. 进程创建过程:
父进程(shell)||-- fork() 创建子进程|   |-- 复制父进程的环境变量表|   |-- 复制父进程的地址空间||-- exec() 加载新程序|-- 保留环境变量表|-- 替换代码和数据
  1. 具体原因:
  • fork()时:

    • 子进程获得父进程环境变量表的完整副本
    • 包括通过export设置的MYENV变量
  • exec()时:

    • 虽然子进程的代码和数据被新程序替换
    • 但环境变量表被保留下来
    • 这是操作系统专门的设计,为了让新程序能够获取环境信息
  1. 系统调用层面:
fork() -> clone()  // 内核复制进程环境表
execve()          // 加载新程序,保留环境变量

这种设计的目的:

  • 允许父进程向子进程传递信息
  • 保持系统配置的一致性
  • 提供进程间简单的通信机制

我们所运行的进程,都是子进程,bash本身在启动的时候,会从操作系统的配置文件中读取环境变量信息,子进程会继承父进程交给我的环境变量。

所以当我们在shellexport一个变量后,通过fork-exec创建的所有子进程都能继承到这个变量。


2.11 常规命令和内建命令

两批命令:

  1. 常规命令 – 通过创建子进程完成的
  2. 内建命令 – bash不创建子进程,而是由自己亲自执行,类似于bash调用了自己写的,或者系统提供的函数。

这两类命令的区别:

  1. 常规命令(外部命令)
  • 存在于文件系统中的可执行文件
  • 执行时会创建子进程
  • 可以通过 which 命令找到其路径
  • 执行效率相对较低
  • 例如:ls, cp, mv, vim
# 查看命令位置
which ls     # 输出: /bin/ls
which cp     # 输出: /bin/cp# 观察进程创建
ps -f        # 执行前
ls /tmp      # 执行外部命令
ps -f        # 可以看到新的进程被创建并结束
  1. 内建命令(内部命令)
  • 内置在 shell 程序中
  • 不需要创建子进程
  • 使用 type 命令可以确认是否为内建命令
  • 执行效率更高
  • 例如:cd, pwd, export, echo
# 查看命令类型
type cd      # 输出: cd is a shell builtin
type echo    # 输出: echo is a shell builtin# 常用内建命令示例
cd /tmp      # 切换目录
pwd          # 显示当前目录
export PATH  # 设置环境变量
source file  # 执行脚本
  1. 两者的具体区别:
# 环境变量的影响
# 外部命令:子进程继承父进程的环境变量
name="john"
export name
ls           # 子进程可以看到 name 变量# 内建命令:直接在当前 shell 中执行
cd /tmp      # 可以直接访问和修改当前 shell 的变量
  1. 常见的内建命令:
# 作业控制
bg          # 后台运行
fg          # 前台运行
jobs        # 显示作业状态# shell 变量操作
export      # 设置环境变量
set         # 设置 shell 变量
unset       # 删除变量# 目录操作
cd          # 改变目录
pwd         # 显示当前目录
dirs        # 显示目录栈# 其他常用内建命令
alias       # 设置命令别名
history     # 显示命令历史
source      # 执行脚本
exit        # 退出 shell
echo        # 显示文本
test        # 条件测试
[           # 条件测试的另一种形式
  1. 查看命令类型的方法:
# 使用 type 命令
type -a cd        # 显示 cd 命令的所有可能位置
type -a echo      # 有些命令既有内建版本也有外部版本
type -a ls        # 显示是外部命令# 使用 which 命令(只对外部命令有效)
which ls          # 显示外部命令的路径
which cd          # 内建命令则找不到路径
  1. 性能对比示例:
# 测试内建命令执行时间
time for i in {1..1000}; do echo "test" > /dev/null; done# 测试外部命令执行时间
time for i in {1..1000}; do /bin/echo "test" > /dev/null; done
# 内建命令通常会快很多

重要说明:

  1. 内建命令的优势:

    • 执行效率高(无需创建子进程)
    • 可以直接修改 shell 环境
    • 启动速度快
  2. 外部命令的特点:

    • 功能通常更专一和强大
    • 需要额外的进程创建和环境设置
    • 可以被替换或更新
  3. 实际应用建议:

    • 对于频繁使用的简单操作,优先使用内建命令
    • 需要复杂功能时,使用专门的外部命令
    • 在脚本中,注意命令类型对性能的影响

2.12 实验

如果只进行 MYENV=“helloworld” ,不调用export导出,在用我们的程序查看,会有什么结果?为什么?

如果只执行 MYENV="helloworld" 而不使用 export,程序将查看不到这个变量。

  1. Shell中变量的两种类型:
  • 本地变量(局部变量)

    • 仅在当前shell中有效
    • 通过 MYENV="helloworld" 设置
    • 不会被子进程继承
  • 环境变量

    • 可以被子进程继承
    • 通过 export MYENV="helloworld" 设置
    • declare -x MYENV="helloworld" 设置
  1. 执行过程对比:
# 设置本地变量
MYENV="helloworld"
./a.out  # 程序输出为空# 设置环境变量
export MYENV="helloworld"
./a.out  # 程序输出 helloworld
  1. 原理说明:
Shell进程|-- MYENV="helloworld" (仅在shell进程中可见)|-- fork()创建子进程|-- 只继承环境变量,不继承本地变量|-- exec()执行新程序|-- getenv()找不到MYENV变量

所以不使用export时,MYENV只是shell的本地变量,不会被放入环境变量表中,因此子进程无法通过getenv()获取到这个变量。


2.13 本地变量和环境变量的主要区别

本地变量:

  • 仅在当前会话/脚本内有效
  • 作用域局限于定义它的 shell 或脚本
  • 子进程无法继承
  • 通常用 变量名=值 的形式定义

环境变量:

  • 对当前shell及其所有子进程都有效
  • 可被子进程继承
  • 使用 export 命令设置
  • 常用于配置系统环境

示例:

# 本地变量
name="john"
echo $name# 环境变量
export PATH="/usr/local/bin:$PATH"
export JAVA_HOME="/usr/lib/jvm/java-8-openjdk"

http://www.ppmy.cn/ops/152247.html

相关文章

微服务学习-Sentinel 限流保护服务

1. 微服务框架为什么要使用流控降级组件&#xff1f; 为了提高系统运行期间的稳定性和可用性。 在微服务环境下&#xff0c;服务之间存在复杂的调用关系&#xff0c;单个服务的故障或过载可能迅速影响到整个系统&#xff0c;导致服务雪崩效应。流控组件可以限制进入系统的流量…

路径规划之启发式算法之二十八:候鸟优化算法(Migrating Birds Optimization, MBO)

候鸟优化算法(Migrating Birds Optimization, MBO)是一种基于群体智能的元启发式优化算法,其灵感来源于候鸟迁徙时的“V”字形飞行队列。这种队列结构能够有效减少能量消耗,同时提高飞行效率。MBO算法通过模拟候鸟的迁徙行为,利用群体间的协作和信息共享来优化问题的解。 …

63,【3】buuctf web Upload-Labs-Linux 1

进入靶场 点击pass1 查看提示 既然是上传文件&#xff0c;先构造一句话木马&#xff0c;便于用蚁剑连接 <?php eval($_POST[123])?> 上传木马 文件后缀写为.php.jpg 右键复制图片地址 打开蚁剑连接 先点击测试连接&#xff0c;显示成功后&#xff0c;再点击添加即可 …

深入 Java Stream 流

目录 一、Stream 流是什么&#xff0c;为啥它如此重要 二、Stream 流的创建 1. 通过集合创建 2. 通过数组创建 3. 使用 Stream.of () 方法 三、Stream 流的中间操作 1. 过滤&#xff08;filter&#xff09; 2. 映射&#xff08;map&#xff09; 3. 排序&#xff08;so…

Gitlab搭建npm仓库

由于图片和格式解析问题&#xff0c;为了更好阅读体验可前往 阅读原文 使用gitlab的仓库注册表特性需要版本14.0&#xff0c;如果你的版本比较低&#xff0c;请先根据自己的需求合理升级后再使用 npm私有仓库的搭建方式有很多种&#xff0c;比如使用docker(阅读此篇)&#xff…

【基础篇】什么是SQL注入,如何防止?

什么是 SQL 注入&#xff0c;如何防止&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是一种常见的网络安全漏洞&#xff0c;它发生在 Web 应用程序中&#xff0c;当恶意用户在输入数据时&#xff0c;将恶意的 SQL 代码插入到输入中&#xff0c;从而导致应用程序…

C++ 中的最大值和最小值判断

1. 使用 std::numeric_limits<T>::max() 和 std::numeric_limits<T>::min() std::numeric_limits 是 C 标准库中的模板类&#xff0c;用于获取各种数据类型的最大值和最小值。它提供了一种通用的方式&#xff0c;适用于所有标准数据类型&#xff08;如 int、long、…

网创资源采集插件自动采集更新网站

现在的资源站越来越多人们对资源的需求也是越来越大但是对站长们来说对对资源的争议是比较耗时的比如大家想开一个网状的资源整合站又比较困难大家需要投入很多的人工经历但是我们如果使用插件自动化的采集发布实验全自动交易是一件非常理想的事情利用插件我们可以实现这一目的…