当前位置: 首页 > article >正文

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

文章目录

  • 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.kler.cn/a/509664.html

相关文章:

  • 麒麟系统下载依赖到本地
  • NLP自然语言处理分词模块HanLP
  • mysql8.0 重要指标参数介绍
  • 鸿蒙动态路由实现方案
  • vue3学习三
  • 32单片机综合应用案例——物联网(IoT)环境监测站(四)(内附详细代码讲解!!!)
  • 一个好用的vue+node后台管理系统
  • -bash: /java: cannot execute binary file
  • JS宏进阶:正则表达式介绍
  • One Prompt is not Enough: Automated Construction of a Mixture-of-Expert Prompts
  • Vue 动态生成响应式表格:优化桌面与移动端展示效果
  • MySQL程序之:使用DNS SRV记录连接到服务器
  • SAP租赁资产解决方案【物业、地产、酒店、汽车租赁行业】
  • GCC支持Objective C的故事?Objective-C?GCC只能编译C语言吗?Objective-C 1.0和2.0有什么区别?
  • PenGymy论文阅读
  • 网络安全(二):加密与认证技术
  • SpringMVC 实战指南:文件上传
  • Java多线程编程:深入理解线程生命周期
  • 1.11 思维树(Tree-of-Thoughts, ToT):续写佳话
  • RK3588平台开发系列讲解(NPU篇)NPU 驱动的组成
  • 时序自适应卷积 (Temporally-Adaptive Convolutions, TAdaConv)详解及代码复现
  • shell-特殊位置变量
  • 关于vite+vue3+ts项目中env.d.ts 文件详解
  • CSRF攻击XSS攻击
  • 基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day2
  • 【Flink系列】2. Flink快速上手