一、学习前言
本次小学期第六节课围绕 Shell 底层原理展开,在此之前我只会零散使用 cd、ls、echo 这类简单终端指令,并不清楚 Shell 到底是什么、终端进程之间存在怎样的父子关系,也分不清内建命令和外部命令的底层区别。本节课全部知识点都在 Xshell 连接 Linux 虚拟机完成实操,过程中记录了操作现象、报错原因、命令运行逻辑,整理成本篇完整学习博客,覆盖 PPT 全部核心知识点,搭建完整知识框架,附带全部可复现操作命令、实操现象分析、课后练习题完整流程,满足本次课程作业发布至 CSDN 的全部要求。
二、Shell 基础概念与各类 Shell 详解
2.1 到底什么是 Shell
Shell 是一门使用 C 语言编写的程序,是普通用户和 Linux 操作系统内核之间的中间桥梁。操作系统内核负责管理硬件资源,但普通用户无法直接和内核交互,所有操作指令都需要通过 Shell 进行翻译转发。
Shell 拥有双重身份:
交互式命令解释语言:也就是我们日常打开 Xshell 终端,在$提示符后输入单行命令,Shell 实时解析、交给内核执行,立刻返回运行结果,我们平时操作虚拟机都使用这种模式。
脚本编程语言:可以把多条连续执行的命令统一写入后缀为.sh的文本文件,形成 Shell 脚本,一次性批量执行大量操作,适合自动化运维、批量处理文件等场景。
简单举例:我们输入ls查看目录文件,不是系统直接执行,是 Shell 先读取ls指令,判断命令类型,再调用对应程序,最后把文件列表输出到终端界面。
2.2 Linux 系统常见 Shell 类型
Linux 发行版内置多种不同版本的 Shell 解释器,语法、功能各有差异,课堂重点讲解主流几种:
Bourne Shell(/bin/sh):最早诞生的标准 Shell,兼容性极强,系统底层脚本大多会使用 sh 解释执行;
Bourne Again Shell(/bin/bash):当前绝大多数 Ubuntu、CentOS 系统默认登录 Shell,在 sh 基础上扩展大量实用功能,支持别名、命令历史、子进程、后台任务等,本节课所有操作均基于 bash;
C Shell(csh):语法风格和 C 语言相似,多用于早期 Unix 系统,国内服务器极少使用;
K Shell(ksh):融合 bash 与 csh 特性,企业大型服务器偶尔使用;
/sbin/sh:专门给 root 超级管理员用户使用的专用 Shell。
2.3 查看与切换 Shell 实操步骤(Xshell 终端执行)
查看当前登录终端正在使用的 Shell:
echo $SHELL
执行后会输出/bin/bash,代表当前默认解释器为 bash。
2. 查看系统全部预装支持的 Shell 程序:
cat /etc/shells
文件内会列出系统所有合法 Shell 路径,包含 bash、dash、sh 等。
3. 查看 /bin 目录下所有以 sh 命名的程序文件,区分软链接与真实程序:
bash
运行
ls -lF /bin/*sh
输出结果中带*代表可执行程序,->代表软链接,比如sh->dash说明系统里 sh 实际指向 dash 程序。
4. 查看用户登录默认 Shell 配置文件
系统所有用户信息存放在/etc/passwd,每行代表一个用户,第七个字段就是该用户登录默认 Shell 程序:
bash
运行
cat /etc/passwd | grep 你的虚拟机用户名
临时切换其他 Shell(以 dash 为例)
输入/bin/dash即可创建子 shell 切换解释器,切换完成后所有命令由 dash 解析;想要回到原本 bash,输入内置命令exit退出当前子 shell。
2.4 Shell 脚本首行声明 #!/bin/bash 详解
当我们编写.sh后缀脚本文件时,文件第一行必须固定填写#!/bin/bash,这行语句不会被当作命令执行,是系统识别标记:
#!是特殊标识符,后续路径/bin/bash代表指定使用 bash 解释器运行当前脚本;同理如果是 Python 脚本可以写#!/usr/bin/python3。
如果省略这一行,系统会使用当前终端默认 Shell 执行脚本,容易出现语法兼容报错,规范编写脚本必须添加该行声明。
三、Shell 父进程与子进程完整解析
3.1 父 Shell、子 Shell 基础定义
父 Shell:打开 Xshell 终端、登录虚拟机后自动生成的交互式 bash 进程,带有$交互提示符,是所有后续衍生 Shell 的父进程,拥有独立 PID(进程 ID);
子 Shell:在父 Shell 中执行特定指令时,系统 fork 创建全新独立 bash 进程,子 Shell 拥有自己的 PID,PPID 字段记录父进程编号,子 Shell 的环境变量、工作目录默认不会反向影响父 Shell。
3.2 会生成子 Shell 的常见场景
终端直接输入bash、dash等 Shell 解释器命令;
使用圆括号()包裹一组命令执行;
命令末尾添加&放入后台运行;
使用coproc协程命令创建后台任务。
3.3 实操验证父子 Shell 嵌套关系
初始状态查看进程树,直观查看进程 PID、父子层级:
ps --forest
输出会以树形排版展示进程,最顶层 bash 即为父 Shell。
2. 连续创建多层嵌套子 Shell:
bash
bash
bash
连续三次输入 bash,相当于在子 shell 内部再次创建子 shell,形成三层嵌套结构。
3. 再次执行进程树查看命令:
ps --forest
此时可以清晰看到树形分层,每一层 bash 都依附上一层父进程,PPID 与上层 PID 对应。
4. 逐层退出子 Shell:每次输入exit只能关闭当前最内层子 shell,多次执行直到回到最初打开终端的父 Shell。
3.4 区分是否存在子 Shell:环境变量BASHSUBSHELL系统内置变量BASH_SUBSHELL 系统内置变量BASHSUBSHELL系统内置变量BASH_SUBSHELL专门用于判断当前是否处于子 shell 环境:
输出数值为 0:当前运行在父 Shell,没有创建子进程;
输出数字大于等于 1:当前处于子 Shell 环境,数字代表嵌套层级。
实操对比演示:
分号分隔单行多命令(不会创建子 shell)
pwd; ls; echo $BASH_SUBSHELL
终端输出结果为 0。
2. 圆括号包裹命令(强制生成子 shell)
(pwd; ls; echo $BASH_SUBSHELL)
终端输出结果为 1,证明新子 shell 已创建;如果括号内部再嵌套一组括号,数值会变为 2。
这里补充实操坑点:在子 shell 内部使用 cd 切换工作目录,只会改变子 shell 自身路径,退出子 shell 后父 Shell 工作目录保持不变,不会同步修改。
四、Shell 四种运行模式实操详解
4.1 分号分隔命令(无新进程,父 Shell 直接执行)
多条无关命令写在同一行,使用英文分号;隔开,命令从上至下顺序执行,全程不创建子 shell,所有操作都在当前父进程完成,适合一次性执行多条简单指令。
mkdir testdir; cd testdir; touch test.txt; ls
4.2 括号进程列表(新建独立子 Shell 执行)
将一组命令整体放入英文圆括号(命令1;命令2),系统会自动创建子 shell 运行括号内所有代码,隔离环境变量、工作目录,适合需要临时切换环境、不影响主终端的操作。
示例:
( mkdir temp; cd temp; echo “子shell测试文件” > demo.txt; ls )
执行结束后,父 Shell 当前目录不会切换到 temp 文件夹。
4.3 后台运行模式 & 后台任务管理
在任意命令末尾添加符号&,该命令会放入后台异步运行,终端不会被占用,我们可以继续输入其他指令。
完整实操流程:
后台执行休眠 60 秒任务
sleep 60 &
终端会输出后台任务编号与进程 PID。
2. 查看当前所有后台运行任务
jobs
查看任务详细PID信息
jobs -l
使用 ps 查看系统全部进程,验证后台 sleep 进程存在
bash
运行
ps -f
等待 60 秒任务执行完毕,按下回车键,终端会自动打印任务完成提示。
4.4 coproc 协程:自定义后台子 shell 任务
coproc 是 bash 高级内置功能,专门在后台生成独立子 shell 执行任务,默认进程名称为 COPROC,支持自定义任务名称,适合需要长期后台运行、独立交互的程序。
默认协程写法:
bash
运行
coproc sleep 10
jobs -l
自定义协程名称(语法严格规范)
大括号{前后必须保留空格,命令末尾必须添加分号,闭合}前同样需要空格,否则直接语法报错:
bash
运行
coproc My_Sleep_Task { sleep 10; }
jobs -l
执行 jobs 可以看到自定义名称的后台协程子 shell。
五、内建命令与外部命令核心区分
5.1 外部命令(文件系统命令)
外部命令是独立的二进制可执行文件,存放在系统/bin、/usr/bin、/sbin等目录中,不属于 bash 程序本身。
运行外部命令时,操作系统会执行 fork 操作创建全新子进程运行程序,开辟独立内存空间,进程创建、销毁存在资源开销,运行速度相对较慢。
常见外部命令:ps、ls、grep、cat。
5.2 内建命令(Shell 内置工具)
内建命令直接编译集成在 bash 程序内部,不存在独立的外部文件,执行时不需要创建子进程,直接在当前 Shell 进程内运行,占用资源少、执行速度更快。
常见纯内建命令:cd、exit、history、alias。
特殊情况:部分命令同时拥有内置版本与外部文件版本,例如 echo、pwd,使用 type 命令可以同时查看两种实现。
5.3 实操区分内外建命令
查看外部命令 ps,定位程序文件路径
bash
运行
which ps
查看命令所有实现(内置+外部)
type -a ps
输出可以看到 ps 存在独立 /usr/bin 程序文件,无内置实现。
2. 查看纯内置命令 cd、exit
bash
运行
type -a cd
type -a exit
终端提示cd is a shell builtin,说明仅存在内置实现,无外部文件。
3. 查看双实现命令 echo、pwd
bash
运行
type -a echo
type -a pwd
输出同时显示 shell builtin 和 /bin/echo,代表两种实现都存在,终端默认优先使用内置版本。
六、两大重点内建命令完整实操(含课后练习题)
6.1 history 历史命令内建命令
history 作用:自动记录当前终端所有输入过的指令,方便快速重复调用历史命令。
核心存储规则:命令操作先临时保存在内存中,只有关闭终端、退出 Shell 会话时,内存中的记录才会写入家目录隐藏文件.bash_history;会话未结束时,新输入命令不会自动同步到文件。
基础操作命令全集