一、Linux 文件系统的核心哲学

一切皆文件

Linux 最根本的设计思想:系统中的一切——硬盘、目录、进程、键盘、网络连接——在操作系统眼里都是"文件"。

/dev/sda       ← 你的硬盘,是个文件
/proc/cpuinfo  ← CPU 信息,是个文件
/etc/passwd    ← 用户账号,是个文件
/home/renbudang/.ssh/id_ed25519  ← SSH 私钥,是个文件

这意味着同一套读、写、移动的操作可以作用于任何对象。你 cat /proc/cpuinfo 就能读 CPU 信息,和读一个 txt 文件没有区别。

单根树结构

Windows 的世界里,每个分区是一个独立的起点(C: / D: / E:)。Linux 的世界里,只有一个根 /,所有的硬盘、U 盘、网络存储都"挂载"到这棵树的某个分支上。

/                          ← 根,一切从这里开始
├── bin/                   ← 系统基础命令(ls、cp、mv 等)
├── boot/                  ← 启动相关文件(内核)
├── dev/                   ← 设备文件(硬盘、键盘、终端)
├── etc/                   ← 配置文件(Nginx、SSH、用户信息)
├── home/                  ← 普通用户的家目录
│   └── renbudang/         ← 你的家目录(~ 就指向这里)
├── tmp/                   ← 临时文件(重启后清空,不保证保留)
├── var/                   ← 变化的数据(日志、网站、数据库)
│   └── www/html/          ← Nginx 默认网站目录
├── proc/                  ← 进程和内核信息(虚拟文件系统,不占磁盘)
└── usr/                   ← 用户安装的软件

路径:绝对 vs 相对

# 绝对路径——从根 / 出发
ls /home/renbudang/myblog/config.yml

# 相对路径——从当前位置出发
# 假设已经在 /home/renbudang 目录下:
ls myblog/config.yml          # 等价于上面那条
ls ./myblog/config.yml        # . 代表"当前目录",等价
ls ../ubuntu/.ssh             # .. 代表"上一级目录",这里等于 /home/ubuntu/.ssh
ls ~/myblog                   # ~ 代表"当前用户的家目录"

判断规则:第一个字符是不是 /

权限三元组

$ ls -l
-rw-rw-r-- 1 renbudang renbudang  6406 Jul 29 13:52 config.yml
 │  │  │
 │  │  └── 其他人的权限(r-- = 只能读)
 │  └── 所属组的权限(rw- = 读写,不能执行)
 └── 文件所有者的权限(rw- = 读写,不能执行)

类型标记:
  -  普通文件
  d  目录
  l  符号链接(快捷方式)

权限字符:
  r  read    读(4)
  w  write   写(2)
  x  execute 执行(1)
  -  没这个权限

rw- = 4+2+0 = 6。所以 chmod 644 file = 所有者读写(6),组只读(4),其他人只读(4)。


二、导航类命令

pwd — 我在哪

pwd
# /home/renbudang/myblog

Print Working Directory。告诉你当前在文件树的哪个节点。迷路了就敲一下。

cd — 去哪

cd /var/log          # 去绝对路径
cd ..                # 回上一级
cd ../..             # 回上两级
cd ~                 # 回家目录
cd -                 # 回上一次在的目录(在 A 和 B 之间反复跳)
cd                   # 不带参数 = cd ~

ls — 这有什么

ls                   # 列出当前目录下的文件和子目录
ls -l                # 长格式:权限、大小、时间
ls -lh               # 长格式 + 人类可读的大小(1K、234M、2G)
ls -a                # 显示隐藏文件(以 . 开头的文件)
ls -A                # 同 -a,但不显示 . 和 .. 两个特殊目录项
ls /var/log          # 列出指定目录的内容

-l-h 可以组合:ls -lh

ll

大多数 Linux 发行版把 ll 设为 ls -l 的别名。你敲 ll,实际执行的是 ls -l


三、查看类命令

cat — 把文件内容打印到屏幕

cat config.yml                    # 整个文件一次打印
cat /proc/cpuinfo                 # 查看 CPU 信息
cat file1.md file2.md > merged.md # 合并两个文件

head / tail — 只看头或尾

head -20 config.yml    # 前 20 行
tail -20 /var/log/nginx/error.log  # 最后 20 行(查日志最常用)
tail -f /var/log/nginx/access.log  # 实时跟踪日志新增内容(Ctrl+C 退出)

四、创建与删除

touch — 创建空文件或更新文件时间戳

touch newfile.md          # 创建一个空的 md 文件
touch existingfile.md     # 如果文件已存在,只更新它的"最后修改时间"

mkdir — 创建目录

mkdir mydir               # 创建一个目录
mkdir -p a/b/c/d          # 一口气创建嵌套的四个目录(不用逐层创建)

rm — 删除文件或目录

rm file.md                # 删文件
rm -r mydir               # 删目录(递归删除里面的所有内容)
rm -rf mydir              # 强制删,不提示确认
rm -rf /var/www/html/*    # 删 html 目录里的所有内容,但保留 html 目录本身

危险区:

rm -rf / var/www/html     # ← / 后面有个空格!系统会先删 /(整个系统),再删指定目录
rm -rf *                  # ← 删掉当前目录下所有东西

永远在敲 rm -rf 前停一秒,确认路径。

cp — 复制

cp source.txt dest.txt         # 复制文件
cp -r source_dir dest_dir      # 复制目录(-r = 递归)
cp file1 file2 dest_dir/       # 复制多个文件到目标目录

mv — 移动或重命名

mv oldname.txt newname.txt     # 重命名
mv file.txt /tmp/              # 移动到 /tmp
mv olddir newdir               # 目录重命名(不需要 -r)

Linux 里没有单独的"重命名"命令——mv 同时干移动和重命名两件事。本质上,“重命名"就是"把文件从原路径移动到新路径”。


五、终端快捷键(不产生文件)

Tab — 自动补全

ls /home/r<Tab>        # 自动补全成 ls /home/renbudang/(如果唯一匹配)

如果多个匹配,按两下 Tab 列出所有可能性:

ls /usr/<Tab><Tab>
# bin/  games/  include/  lib/  local/  sbin/  share/  src/

Ctrl+C — 终止当前运行的程序

hugo server        # 启动后就卡在终端里了
# 按 Ctrl+C → 程序停止,回到命令提示符

不是"撤销",是"强制停止正在跑的程序"。

Ctrl+U — 清掉当前行

$ rm -rf /etc/nginx/很长的路径打错了想重来
# 按 Ctrl+U → 整行清空,光标回到行首

比按住 Backspace 删半天快得多。


六、命令组合模式

管道 | — 把一个命令的输出喂给另一个命令

ls -l | grep config        # ls 的输出 → 只保留包含 "config" 的行
cat access.log | wc -l     # 统计日志有多少行
docker ps | grep dvwa      # 在运行中容器里找 dvwa

重定向 > / >> — 把输出写到文件

ls -l > filelist.txt       # 覆盖写入
ls -l >> filelist.txt      # 追加写入(不覆盖原有内容)
echo "hello" > new.txt     # 创建文件并写入一行

七、实践建议

# 日常最常用的五个命令:
ls -lh      # 看看这都有啥
cd 路径     # 换个地方
cat 文件名   # 快速看一眼文件内容
mv A B      # 移动或改名
rm 文件     # 删除

# 遇到问题时的自救三步:
pwd         # 先确认自己在哪
ls -la      # 看看当前目录有什么(含隐藏文件)
history     # 看看刚才敲了什么命令

八、rm -rf /* vs rm -rf * — 两个危险命令的区别

rm -rf /* — 从根目录开始删

/*  = 根目录下的所有东西
    = /bin + /boot + /dev + /etc + /home + /tmp + /var + /usr + ...

rm -rf /*  → 从根 / 出发,遍历所有子目录,全部递归强制删除
           → 内核还在内存里跑,但磁盘上的系统文件全没了
           → 机器不会立刻死,但任何新的命令、读写操作都会失败
           → 这就是"删库跑路"的原型

rm -rf * — 从当前目录开始删

*  = 当前目录下的所有东西(不包含隐藏文件)

假设你在 /home/renbudang/ 下执行:
rm -rf *  → 删掉 myblog/、各类配置文件、所有可见文件
          → /home/renbudang/ 变成空目录
          → 系统文件(/bin、/etc 等)完好无损

核心区别

rm -rf /* rm -rf *
起删点 根目录 / 当前目录
影响范围 整个系统 当前目录下的可见内容
星号含义 根目录下的所有内容 当前目录下的所有内容
跟正则有关吗 无关——* 是 shell 的通配符(globbing),不是正则表达式

九、rm -rf .* 为什么危险

.* 展开后包含 ..

当前你在 /home/renbudang/myblog/

Shell 把 .* 展开:
  .        ← 当前目录 /home/renbudang/myblog/
  ..       ← 上一级目录 /home/renbudang/
  .gitignore  ← 隐藏文件

rm -rf .. 会导致递归删除上一级目录 /home/renbudang/现代 GNU rm 会拒绝删除 ...,但不应依赖这个保护——老系统、某些 Docker 镜像里的 rm 可能没有这个检查。

安全的删除隐藏文件写法:

rm -rf .[!.]*    # 以 . 开头,第二位不能是 .,排除了 . 和 ..

十、Shell 通配规则(Globbing)

Shell 在把命令交给 rm(或 lscp之前,自己先做文件名展开。这个过程叫 globbing*?[...] 叫 glob pattern,不是正则表达式

三条基本运算符

运算符 匹配什么 例子 展开结果
* 任意长度的任意字符(除了以 . 开头 *.md a.mdconfig.md,不匹配 .hidden.md
? 任意一个字符 file?.txt file1.txtfileA.txt,不匹配 file12.txt
[...] 方括号里的一个字符 file[0-9].txt file1.txtfile5.txt,不匹配 fileA.txt

* 的两条硬规则

规则一:* 匹配任意字符序列,长度可以为 0

规则二:* 不会穿过 /(不能跨目录层级匹配)

规则三:以 . 开头的文件名不会被 * 匹配(这是有意为之的设计约定)

为什么 * 不匹配隐藏文件

这是 Unix 设计者有意为之的约定,不是技术限制。每个目录里必然存在 ... 两个特殊目录项,设计者想让 ls 和通配符默认忽略它们,于是定了一条规则:. 开头的文件名是"隐藏"的,* 不匹配它们。

四十年来所有类 Unix 系统都遵守这个约定。

.* 展开规则

.* 就是一个字面点号 . 后面跟一个 *

.   ← 固定的、字面的点号(文件名第一个字符必须是 .)
*   ← 后面跟任意字符序列(包括空)

展开逻辑:在当前目录下找所有以 . 开头的名字。... 恰好也以点开头——所以它们也被包括在内。

echo .*
# 展开为:echo . .. .bashrc .gitconfig .local .ssh

. 在 glob 里只是一个普通字面字符,没有任何特殊含义。它不像正则表达式里 . 代表"任意字符"。

展开时机

Shell 在敲回车之后、命令启动之前完成展开。

ls *.md
  → Shell 先:把 *.md 替换成当前目录下所有匹配的文件名
  → Shell 执行:ls a.md config.md readme.md
  → ls 收到的参数里已经看不到 * 了——星号是 shell 的事,跟 ls 无关

常用通配组合速查

模式 匹配 危险程度
* 所有非隐藏文件 🟢 安全
.* 所有隐藏文件 + . + .. 🔴 危险(含 ..
.[!.]* 所有隐藏文件,排除 ... 🟢 安全
*.* 文件名里必须有 .file.txt ✓,Makefile ✗) 🟢 安全
*.{md,yaml} brace expansion 先展开为 *.md *.yaml 🟢 安全
/* 根目录下所有内容 🔴🔴🔴 致命

下一篇:Linux 文件编辑(vim / nano / VS Code Remote)与文件搜索(find / grep)