本模块以一道高频面试题"rm -rf / 的作用是什么?"为引子,系统讲解 Linux 的目录结构、文件管理指令以及 Shell 与文件系统的抽象关系。掌握这部分内容,一方面可以应对真实工作场景,另一方面也能为学习操作系统底层知识打下基础。
预警:请勿在真实服务器上运行
rm -rf /,本文仅用于理解指令语义。
rm -rf / 的作用Shell 把我们输入的指令传递给操作系统去执行,是命令行的用户界面。早期程序员没有图形界面可用,就用 Shell;而且图形界面制作成本较高、不能实现所有功能,因此今天的程序员依然使用 Shell。你经常听到的 bash(Bourne Again Shell)就是一种 Shell 程序:Steve Bourne 最早编写了 Bourne shell(sh),bash 是 GNU 项目对它的重新实现与扩展(由 Brian Fox 编写)。
本模块涉及的指令,并非写死在操作系统中,而是一个个独立程序。例如 rm 指令,可以用 which 查看它所在的目录,通常位于 /usr/bin/rm。连接用户和操作系统的程序就是 Shell。
Linux 将文件组织为树状结构,/ 代表根目录,每级目录也用 / 分隔。例如在 /usr/bin/rm 中,第一级是 / 根目录,第二级是 usr,第三级是 bin,最后的 rm 是一个文件。
/usr/bin/rm 称为可执行文件 rm 的路径(Path)。路径就是一个文件在文件系统中的地址;因为文件系统是树形结构,通常一个文件只有一个地址(路径)。
/ 开始,每一层都是一级子目录,直到定位到目标文件为止。/usr/bin/rm 就是一个绝对路径。Shell 抽象出工作目录(Working Directory)方便用户操作。当用户打开 Shell 时,Shell 会分配一个工作目录,因此产生相对路径(Relative Path)——以工作目录为基点的路径。例如:
/usr 目录下时,rm 的相对路径是 bin/rm;/usr/bin 目录下时,路径是 ./rm 或 rm,. 代表当前目录;/usr/bin/somedir 下时,相对路径是 ../rm,.. 代表上一级目录。cd(change directory)用于切换工作目录,既可用绝对路径也可用相对路径,注意:
cd 不带参数会切换到用户家目录,Linux 中通常是 /home/{用户名};cd . 什么都不会发生,因为 . 代表当前目录;cd .. 会回退一级目录,因为 .. 代表上级目录。pwd(Print Working Directory)用于查看当前工作目录。
上图展示了 Linux 树状目录与路径寻址的关系:从根 / 一路向下定位到具体文件,如 /usr/bin/rm;同一文件可用绝对路径亦可结合工作目录用相对路径描述。理解这张树状图是掌握所有文件管理指令的基础。
Linux 中目录也是一种文件,常见文件类型有以下 7 种:
/ 也是文件);rm);使用 ls -F 可查看当前目录下文件的类型标识:* 结尾为可执行文件、= 结尾为 Socket 文件、@ 结尾为软链接、| 结尾为管道文件、/ 结尾为目录、无符号结尾为普通文件。
Linux 不只把 Socket 抽象成文件,设备也都抽象成了文件,因为设备需要不断与操作系统交换数据,而交换方式只有读和写两种。例如打印机、USB、显卡等都被抽象成文件。这让整体系统设计高度统一。
上图为文件管理的基本操作闭环:创建使用 touch(文件)与 mkdir(目录),查看用 ls/pwd/ls -l,修改用 vi/nano 编辑器,删除用 rm/rm -r,内容查阅则按数据量在 cat、more、less、head、tail、grep 之间选择。
当文件较小时(如配置文件),可用 cat 快速浏览;cat 会将文件连接到标准输出流(Standard Output)并打印到屏幕。标准输出流也是一种文件,进程可将内容写入后打印输出。
但对于动辄几个 G 的线上日志,直接用 cat 会有两个问题:其一,把文件拷贝到输入输出流耗时且占用机器资源;其二,文件整体读入内存会大量占用内存,可能导致其他应用内存不足。因此需要 more/less/head/tail 这类只读取所需部分到内存的指令。
# touch 创建空文件(若不存在);本意是修改时间戳
touch a.txt
# 修改文件的时间戳;如果文件不存在则触发创建
# 若文件已存在则更新其时间
# mkdir 创建目录;-p 表示父级目录不存在时递归创建
mkdir hello
mkdir -p hello/world # 递归创建多级目录
man是 manual(说明书)的缩写,指的是系统手册。拿到陌生指令(如touch)时可用man touch查阅帮助;不熟悉man也可用man man。
# ls(list 缩写)显示文件信息
ls
# pwd 查看当前工作目录
pwd
# ls -l 显示更详细的信息(所有者、分组、大小、日期等)
ls -l
# 目录文件 Linux 默认分配 4096 字节空间,因为目录内需保存许多文件的描述信息# 删除文件
rm a.txt
# 删除目录:必须加 -r(recursive,递归),目录是递归结构
rm hello
# 会提示 hello 是目录,不可删除
rm -r hello # 递归删除 hello 目录# 使用 nano 或 vi 编辑器修改文件(一般 Linux 自带)
nano file.txt
vi file.txt# cat:适合小文件,将内容打印到标准输出流
cat /etc/hosts
# more:阅读过滤器,只读取需要部分到内存,支持向下翻页、输入文本搜索
more /var/log/11-Nginx基础概述/access.log
# 在 more 中输入 / 再输入关键字,可定位匹配内容
# less:与 more 功能类似(man 中自述是 more 的反义词),支持向上翻页
less /var/log/11-Nginx基础概述/access.log
# head/tail:读取头 N 行或尾 N 行
head -n 20 /var/log/11-Nginx基础概述/access.log
tail -n 1000 /var/log/11-Nginx基础概述/access.log # 服务异常时查看最后 1000 行
# tail -f:实时跟随输出(-f 是 follow,文件追加内容会跟随输出)
tail -f /var/log/11-Nginx基础概述/access.loggrep 可拆分为 g|re|p:g 是 global(全局)、re 是 regular expression(正则表达式)、p 是 print(打印)。作用是通过正则表达式全局搜索文件并打印匹配的行。
# 例 1:查找指定 IP
grep "192.168.x.x" /var/log/11-Nginx基础概述/access.log
# 例 2:查找某时间段日志
grep "2024/01/15:10:0" /var/log/11-Nginx基础概述/access.log# which:查询某个指令文件的位置
which grep
# 结果通常为 /usr/bin/grep
which rm
# /usr/bin/rm
# find:在文件系统中查找文件
find / -iname "*.txt"
# -iname 用于匹配查找,i 代表忽略大小写,也可用 -name 替代| 指令 | 作用 |
|---|---|
pwd | 查看工作目录 |
cd | 切换工作目录 |
which | 查找一个执行文件所在的路径 |
ls | 显示文件信息 |
rm | 删除文件 |
touch | 修改文件时间戳,文件不存在则创建 |
vi / nano | 编辑文件 |
cat | 查看完整文件,适合小型文件 |
more / less | 只读取看到的内容到内存,适合服务器看日志 |
head / tail | 看文件的头和尾 |
grep | 搜索文件内容 |
find | 全局查找文件 |
强调:
man是所有指令的手册,务必多多运用并熟练掌握。一个指令通常有非常多的参数,都需要用man去仔细研究。
rm -rf / 意为强制递归删除整个文件系统上的所有文件且不提示,属于极高危操作。生产环境应谨慎使用 rm,涉及目录删除务必先 ls 确认路径;-r 与 -f 的具体含义见第六节面试题解析。牢铸防线:任何环境都不要执行 rm -rf /。
思考后请对照下列拆解:
/:文件系统根目录;rm:删除指令(remove);-r:recursive(递归),删除目录时需递归处理;-f:force(强制),遇到只读文件也不提示,直接删除。所以 rm -rf / 就是强制递归删除整个文件系统上的所有文件,且不向用户给出任何提示。这是一条会摧毁整个系统的指令,任何场景下都不应执行。
搜索文件系统中所有包含 std 字符串且以 .h 扩展名结尾的文件。(提示:可结合 find 与通配符匹配。)
find / -iname "*std*.h"man bash、man find、man greprm 误删数据恢复,可参考 02-实战与排障 分类的《磁盘数据恢复:rm -rf 误删数据,如何进行数据恢复》一篇