Comprehensive Study Notes
Linux
完整知识体系
从文件系统到内核调优,覆盖 Linux 全部核心知识点、运维难点与高频易错陷阱。适用于系统管理员、后端开发者及 DevOps 工程师。
01
系统概述与哲学
1.1 Linux 核心哲学
- 一切皆文件 — 硬件、进程、网络套接字都通过文件接口访问
- 小而美 — 每个程序只做一件事,做好一件事
- 组合优于单体 — 通过管道
|组合简单工具完成复杂任务 - 文本为王 — 配置文件几乎都是纯文本
- 透明性 — 系统行为可观察、可调试、可预测
1.2 系统架构概览
# Linux 系统层次
┌─────────────────────────────────┐
│ 用户空间 (User Space) │ ← 应用程序、Shell、服务
├─────────────────────────────────┤
│ 系统调用接口 (System Call) │ ← open(), read(), write(), fork()
├─────────────────────────────────┤
│ 内核 (Kernel) │ ← 进程调度、内存管理、VFS、网络栈
├─────────────────────────────────┤
│ 硬件抽象层 (HAL) │ ← 驱动程序
├─────────────────────────────────┤
│ 硬件 (Hardware) │ ← CPU、内存、磁盘、网卡
└─────────────────────────────────┘
1.3 常见发行版
| 分支 | 代表 | 包管理 | 适用场景 |
|---|---|---|---|
| Debian 系 | Ubuntu, Debian, Mint | apt / dpkg | 桌面、云服务器 |
| RHEL 系 | CentOS, Rocky, Alma | yum / dnf | 企业服务器 |
| Arch 系 | Arch, Manjaro | pacman | 极客、滚动更新 |
| Alpine | Alpine Linux | apk | 容器镜像 |
02
文件系统与目录
2.1 目录层次标准 (FHS)
# Linux 目录树结构
/
├── bin → 基本用户命令 (ls, cp, mv)
├── sbin → 系统管理命令 (fdisk, iptables)
├── etc → 系统配置文件
├── home → 用户主目录
├── root → root 用户主目录
├── var → 可变数据 (日志、缓存、数据库)
│ ├── log
│ ├── cache
│ └── tmp
├── tmp → 临时文件(重启可能清空)
├── usr → 用户级程序和数据(只读)
│ ├── bin
│ ├── lib
│ └── share
├── opt → 第三方软件安装目录
├── proc → 虚拟文件系统(进程信息)
├── sys → 虚拟文件系统(设备/内核信息)
├── dev → 设备文件 (硬盘、终端)
├── mnt → 临时挂载点
├── boot → 启动文件(内核、grub)
├── lib → 共享库文件
└── media → 可移动设备挂载点
2.2 文件系统类型
| 文件系统 | 特点 | 适用场景 |
|---|---|---|
ext4 | 成熟稳定,支持日志 | 通用 Linux 默认 |
xfs | 高性能,适合大文件 | 数据库、大容量存储 |
btrfs | 快照、压缩、校验 | 高级存储需求 |
tmpfs | 内存文件系统 | /tmp, /dev/shm |
nfs | 网络文件系统 | 网络共享存储 |
squashfs | 只读压缩 | Live CD、容器 |
2.3 inode 与硬链接/软链接
# inode 是文件的元数据(权限、大小、位置等),不包含文件名
ls -i file.txt # 查看 inode 号
df -i # 查看 inode 使用情况
# 硬链接:同一 inode,多个文件名
ln file.txt hardlink.txt # 硬链接
# 软链接(符号链接):独立文件,指向目标路径
ln -s file.txt symlink.txt # 软链接
易错点 · 硬链接 vs 软链接
| 特性 | 硬链接 | 软链接 |
|---|---|---|
| 跨文件系统 | 不可以 | 可以 |
| 链接目录 | 不可以 | 可以 |
| 删除原文件 | 仍可访问 | 断链(红色闪烁) |
| inode | 相同 | 不同 |
| 文件大小 | 与原文件相同 | 路径字符串长度 |
删除原文件后,硬链接数据仍然存在(inode 引用计数 > 0)。软链接会变成悬空引用。
03
文件与目录操作
3.1 导航与查看
pwd # 当前目录
cd /path/to/dir # 切换目录
cd - # 回到上一个目录
cd ~ # 回到家目录
ls -la # 详细列表(含隐藏文件)
ls -lh # 人类可读的文件大小
ls -lt # 按修改时间排序
ls -lS # 按大小排序
tree -L 2 # 树形结构(2层深度)
3.2 文件操作
# 创建
touch file.txt # 创建空文件 / 更新时间戳
mkdir -p /a/b/c # 递归创建目录
mktemp # 创建临时文件
# 复制
cp file.txt /backup/ # 复制文件
cp -r dir/ /backup/ # 递归复制目录
cp -a dir/ /backup/ # 归档复制(保留权限、时间戳、链接)
rsync -avz src/ dest/ # 增量同步(本地/远程)
# 移动 / 重命名
mv old.txt new.txt # 重命名
mv file.txt /other/dir/ # 移动
# 删除(极度危险!)
rm file.txt # 删除文件
rm -r dir/ # 递归删除目录
rm -rf dir/ # 强制递归删除(不提示!)
rmdir empty_dir # 只删空目录
易错点 · rm -rf / 的灾难
# 永远不要执行(尤其是 root 下):
rm -rf / # 删除整个系统
rm -rf /* # 同上
rm -rf ~ # 删除家目录
# 安全习惯:先 ls 再 rm
ls /tmp/to_delete/ # 先确认内容
rm -rf /tmp/to_delete/ # 再删除
# 加 -i 交互确认
rm -ri dir/ # 每个文件都会确认
生产环境建议使用 trash-cli(trash-put)代替 rm,给自己一个后悔的机会。
3.3 查找文件
# find — 最强大的文件查找
find / -name "*.log" # 按名称
find /var -type f -size +100M # 大于100M的文件
find /tmp -mtime +7 -delete # 删除7天前的文件
find . -name "*.py" -exec grep -l "TODO" {} \; # 查找含TODO的Python文件
find / -perm -4000 # 查找 SUID 文件
# locate — 基于数据库的快速查找(需 updatedb)
locate nginx.conf
# which / whereis
which python3 # 查找命令路径
whereis nginx # 查找命令、源码、手册
# type — 查看命令类型
type cd # cd is a shell builtin
type ls # ls is aliased to 'ls --color=auto'
04
权限与所有权
4.1 权限模型
# ls -l 输出解读
-rwxr-xr-- 1 Ginc devs 4096 Jan 15 10:30 script.sh
│└┬┘└┬┘└┬┘ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ └─ 文件名
│ │ │ │ │ │ │ │ └─ 修改时间
│ │ │ │ │ │ │ └─ 文件大小
│ │ │ │ │ │ └─ 所属组
│ │ │ │ │ └─ 所有者
│ │ │ │ └─ 硬链接数
│ │ │ └─ 其他用户 (r-- = 只读)
│ │ └─ 所属组 (r-x = 读+执行)
│ └─ 所有者 (rwx = 读+写+执行)
└─ 文件类型 (- 普通文件, d 目录, l 链接, c 字符设备, b 块设备)
4.2 chmod — 修改权限
# 数字模式(八进制)
chmod 755 script.sh # rwxr-xr-x
chmod 644 config.txt # rw-r--r--
chmod 600 secret.key # rw-------
chmod 777 public/ # rwxrwxrwx(危险!)
# 符号模式
chmod u+x script.sh # 给所有者加执行权限
chmod g-w file.txt # 去掉组的写权限
chmod o=r file.txt # 其他用户只读
chmod a+r file.txt # 所有人加读权限
chmod -R 755 /var/www/ # 递归修改
# 常用权限速记
# 755 → 脚本/目录(所有者全权限,其他人读+执行)
# 644 → 配置文件(所有者读写,其他人只读)
# 600 → 私密文件(仅所有者读写)
# 700 → 私密目录(仅所有者访问)
难点 · 权限的数字计算
# r = 4, w = 2, x = 1 → 相加
# rwx = 4+2+1 = 7
# r-x = 4+0+1 = 5
# r-- = 4+0+0 = 4
# --- = 0+0+0 = 0
# 755 = rwx(7) r-x(5) r-x(5)
# 644 = rw-(6) r--(4) r--(4)
4.3 特殊权限位
| 权限 | 符号 | 数字 | 作用 | 示例 |
|---|---|---|---|---|
| SUID | s (user x 位) | 4 | 以文件所有者身份运行 | /usr/bin/passwd |
| SGID | s (group x 位) | 2 | 以文件所属组身份运行;目录下新文件继承组 | 共享目录 |
| Sticky Bit | t (other x 位) | 1 | 只有所有者能删除自己的文件 | /tmp |
chmod 4755 /usr/bin/myapp # 设置 SUID
chmod 2755 /shared/ # 设置 SGID
chmod 1755 /tmp # 设置 Sticky Bit
find / -perm -4000 -ls # 查找所有 SUID 文件(安全审计)
4.4 chown / chgrp
chown Ginc file.txt # 修改所有者
chown Ginc:devs file.txt # 同时修改所有者和组
chown :devs file.txt # 只修改组
chown -R Ginc:devs /var/www/ # 递归修改
chgrp devs file.txt # 修改所属组
易错点 · 目录的执行权限
目录的 x 权限表示能否进入(cd)该目录,而非执行。没有 x 权限的目录无法访问其中的任何文件,即使文件本身权限允许。r 权限只允许列出文件名,要真正读取文件内容还需要 x。
05
用户与组管理
5.1 用户操作
# 创建用户
useradd -m -s /bin/bash -G sudo,docker Ginc # 创建用户,指定shell和附加组
passwd Ginc # 设置密码
# 修改用户
usermod -aG docker Ginc # 追加到 docker 组(-a 必须!)
usermod -s /bin/zsh Ginc # 修改默认 shell
usermod -L Ginc # 锁定账户
usermod -U Ginc # 解锁账户
# 删除用户
userdel Ginc # 删除用户(保留家目录)
userdel -r Ginc # 删除用户和家目录
# 查看用户信息
id Ginc # uid, gid, groups
whoami # 当前用户
who # 当前登录的所有用户
last # 最近登录记录
易错点 · usermod -aG
usermod -G docker Ginc(没有 -a)会覆盖所有附加组,只保留 docker!必须用 -aG 追加。这是一个非常常见的事故原因。
5.2 关键文件
| 文件 | 内容 | 格式 |
|---|---|---|
/etc/passwd | 用户信息 | name:x:uid:gid:comment:home:shell |
/etc/shadow | 密码哈希 | 仅 root 可读 |
/etc/group | 组信息 | name:x:gid:members |
/etc/sudoers | sudo 权限 | visudo 编辑 |
5.3 sudo
# /etc/sudoers 示例(用 visudo 编辑!)
Ginc ALL=(ALL:ALL) ALL # 完整 sudo 权限
bob ALL=(ALL) NOPASSWD: ALL # 免密 sudo
%devs ALL=(ALL) /usr/bin/systemctl # devs 组只能用 systemctl
06
Shell 基础与变量
6.1 常见 Shell
| Shell | 特点 |
|---|---|
bash | 最广泛,兼容 sh,Linux 默认 |
zsh | 更强的自动补全、主题支持(Oh My Zsh) |
sh | POSIX 标准,最基础 |
fish | 开箱即用的语法高亮、自动建议 |
dash | 轻量快速,Ubuntu 的 /bin/sh |
6.2 变量
# 定义变量(等号两边不能有空格!)
name="Linux" # 正确
name = "Linux" # 错误!会把 name 当作命令
# 使用变量
echo $name
echo ${name}_server # 用花括号明确边界
# 变量类型
local_var="local" # 局部变量(仅当前 Shell)
export GLOBAL_VAR="global" # 环境变量(子进程可见)
readonly CONST="immutable" # 只读变量
# 特殊变量
$0 # 脚本名称
$1 $2 $3 # 第1、2、3个参数
$# # 参数个数
$@ # 所有参数(各自独立)
$* # 所有参数(作为一个字符串)
$? # 上一条命令的退出状态码
$$ # 当前 Shell 的 PID
$! # 最后一个后台进程的 PID
易错点 · 变量定义空格
# 正确
name="Ginc"
# 错误(会尝试执行 name 命令)
name = "Ginc" # bash: name: command not found
6.3 引号的区别
name="World"
echo "Hello, $name" # Hello, World ← 双引号:变量展开
echo 'Hello, $name' # Hello, $name ← 单引号:原样输出
echo Hello, \$name # Hello, $name ← 反斜杠:转义单个字符
# 命令替换
echo "Today is $(date +%Y-%m-%d)" # 反引号 `` 也可,但 $() 更推荐
echo "Files: `ls | wc -l`" # 反引号(不推荐嵌套)
07
重定向与管道
7.1 标准流
| 文件描述符 | 名称 | 缩写 | 默认设备 |
|---|---|---|---|
| 0 | 标准输入 stdin | < | 键盘 |
| 1 | 标准输出 stdout | > | 屏幕 |
| 2 | 标准错误 stderr | 2> | 屏幕 |
7.2 重定向
# 输出重定向
echo "hello" > file.txt # 覆盖写入
echo "world" >> file.txt # 追加写入
command 2> error.log # 重定向错误
command > out.log 2>&1 # 合并 stdout 和 stderr
command &> all.log # 同上(Bash 简写)
command > /dev/null 2>&1 # 丢弃所有输出
# 输入重定向
mysql -u root < database.sql # 从文件读取输入
# Here Document
cat <<EOF > config.txt
server=192.168.1.1
port=8080
EOF
# Here String
grep "error" <<< "this is an error message"
难点 · 2>&1 的顺序
# 正确:先把 stderr 指向 stdout 的位置,再把 stdout 写入文件
command > file.log 2>&1
# 错误:此时 stderr 指向屏幕,后面再重定向 stdout 不影响 stderr
command 2>&1 > file.log # stderr 仍在屏幕!
记住:重定向从左到右依次执行。2>&1 放在 > file 之前时,1 还指向屏幕,所以 stderr 也指向屏幕。
7.3 管道与 xargs
# 管道:前一个命令的 stdout 作为后一个命令的 stdin
cat access.log | grep "404" | wc -l
# 管道不传递 stderr
ls /nonexist | cat # cat 不会收到错误信息
ls /nonexist 2>&1 | cat # 先合并再管道
# xargs — 将 stdin 转为命令参数
find . -name "*.log" | xargs rm # 删除找到的文件
find . -name "*.log" | xargs -I {} mv {} /backup/ # 占位符
cat urls.txt | xargs -P 4 -I {} curl -sO {} # 4并发下载
易错点 · 文件名带空格
# find + xargs 遇到空格文件名会出错
find . -name "*.txt" | xargs rm # "my file.txt" 会拆成两个参数
# 安全写法
find . -name "*.txt" -print0 | xargs -0 rm # 用 null 分隔
08
文本处理三剑客
8.1 grep — 搜索
grep "error" logfile.txt # 搜索含 error 的行
grep -i "error" logfile.txt # 忽略大小写
grep -r "TODO" /project/ # 递归搜索目录
grep -n "error" logfile.txt # 显示行号
grep -c "error" logfile.txt # 统计匹配行数
grep -v "debug" logfile.txt # 反向匹配(排除)
grep -w "error" logfile.txt # 全词匹配
grep -E "error|warn" logfile.txt # 扩展正则(egrep)
grep -A 3 "error" logfile.txt # 匹配行后3行
grep -B 2 "error" logfile.txt # 匹配行前2行
grep -C 2 "error" logfile.txt # 匹配行前后各2行
grep --include="*.py" -r "import" . # 只搜索 .py 文件
8.2 sed — 流编辑器
# 替换
sed 's/old/new/' file.txt # 替换每行第一个
sed 's/old/new/g' file.txt # 替换所有(g=全局)
sed -i 's/old/new/g' file.txt # 原地修改(-i 直接改文件)
sed -i.bak 's/old/new/g' file.txt # 原地修改并备份为 .bak
# 删除
sed '3d' file.txt # 删除第3行
sed '/pattern/d' file.txt # 删除匹配行
sed '/^$/d' file.txt # 删除空行
# 插入/追加
sed '2i\新行内容' file.txt # 第2行前插入
sed '2a\新行内容' file.txt # 第2行后追加
# 提取
sed -n '10,20p' file.txt # 打印第10~20行
sed -n '/start/,/end/p' file.txt # 打印 start 到 end 之间的内容
# 多个操作
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
8.3 awk — 文本分析
# 基本语法: awk 'pattern { action }' file
# 打印特定列(默认空格/Tab分隔)
awk '{print $1, $3}' file.txt # 第1列和第3列
awk -F: '{print $1}' /etc/passwd # 指定分隔符为 :
# 条件过滤
awk '$3 > 100 {print $1, $3}' data.txt # 第3列大于100的行
awk '/error/ {print}' logfile.txt # 包含 error 的行
# 内置变量
awk '{print NR, NF, $0}' file.txt # 行号, 字段数, 整行
awk 'END {print NR}' file.txt # 总行数
# 统计求和
awk '{sum += $3} END {print sum}' data.txt # 第3列求和
# 实战:统计 Nginx 日志每个 IP 的请求数
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20
# 格式化输出
awk '{printf "%-20s %10d\n", $1, $3}' data.txt
知识点 · 其他文本工具
| 工具 | 用途 | 示例 |
|---|---|---|
sort | 排序 | sort -t: -k3 -n /etc/passwd 按 UID 排序 |
uniq | 去重(需先排序) | sort file | uniq -c 统计频次 |
cut | 按列截取 | cut -d: -f1,3 /etc/passwd |
tr | 字符替换 | echo "ABC" | tr 'A-Z' 'a-z' |
tee | 同时输出到屏幕和文件 | cmd | tee log.txt |
wc | 计数 | wc -l file 统计行数 |
diff | 比较文件差异 | diff -u old new |
jq | JSON 处理 | cat data.json | jq '.users[].name' |
09
Shell 脚本编程
9.1 脚本基础
#!/bin/bash
# ↑ Shebang 行:指定解释器,必须在第一行
# 没有 shebang 时用当前 Shell 执行
# 调试模式
bash -x script.sh # 打印每条执行的命令
set -x # 脚本内开启调试
set -e # 遇到错误立即退出
set -u # 使用未定义变量时报错
set -euo pipefail # 推荐组合:严格模式
9.2 条件判断
# if 语法
if [ "$a" -eq "$b" ]; then
echo "相等"
elif [ "$a" -gt "$b" ]; then
echo "$a 更大"
else
echo "$b 更大"
fi
# 数值比较
-eq # 等于 -ne 不等于
-gt # 大于 -lt 小于
-ge # 大于等于 -le 小于等于
# 字符串比较
= # 等于 != 不等于
-z # 为空 -n 非空
# 文件测试
-f file # 是否为文件
-d dir # 是否为目录
-e path # 是否存在
-r file # 是否可读
-w file # 是否可写
-x file # 是否可执行
-s file # 是否非空
file1 -nt file2 # file1 是否比 file2 新
# [[ ]] 是增强版(Bash 推荐)
if [[ "$str" =~ ^[0-9]+$ ]]; then
echo "是数字" # 支持正则匹配
fi
# 逻辑组合
if [ "$a" -gt 0 ] && [ "$a" -lt 100 ]; then ...
if [[ "$a" > 0 && "$a" < 100 ]]; then ...
易错点 · [ ] 中的空格
# 正确(方括号内侧必须有空格)
if [ "$a" -eq "$b" ]; then
# 错误(各种空格问题)
if ["$a"-eq"$b"]; # 语法错误
if [ $a -eq $b ] # 变量为空时会崩溃!
# 最佳实践:始终双引号引用变量
if [ "$a" -eq "$b" ] # ✓ 安全
9.3 循环
# for 循环
for i in 1 2 3 4 5; do
echo "$i"
done
for i in {1..100}; do echo "$i"; done
for file in *.log; do
echo "Processing $file"
done
for ((i=0; i<10; i++)); do
echo "$i"
done
# while 循环
while IFS= read -r line; do
echo "$line"
done < file.txt
# 逐行读取文件(推荐上面的方式,保留空格和反斜杠)
while IFS= read -r line; do
echo "Line: $line"
done < /etc/passwd
9.4 函数
# 定义函数
greet() {
local name="$1" # local 声明局部变量
local greeting="${2:-Hello}" # 参数默认值
echo "$greeting, $name!"
return 0 # 返回状态码(不是值!)
}
greet "Ginc" # Hello, Ginc!
greet "Bob" "Hi" # Hi, Bob!
# 函数返回值只能通过 echo + 命令替换获取
add() {
echo $(( $1 + $2 )) # 输出结果
}
result=$(add 3 5) # 捕获输出
echo "$result" # 8
10
进程管理
10.1 查看进程
ps aux # 所有进程(BSD 风格)
ps -ef # 所有进程(System V 风格)
ps aux | grep nginx # 查找特定进程
ps -eo pid,ppid,user,%cpu,%mem,cmd --sort=-%cpu | head -20 # CPU Top 20
top # 实时进程监控
htop # 增强版 top(需安装)
pstree # 进程树
pstree -p # 带 PID 的进程树
10.2 进程控制
command & # 后台运行
nohup command & # 后台运行,不受终端关闭影响
jobs # 查看后台任务
fg %1 # 切到前台
bg %1 # 继续后台运行
# 发送信号
kill PID # 发送 SIGTERM (15) — 优雅终止
kill -9 PID # 发送 SIGKILL (9) — 强制终止
kill -HUP PID # 发送 SIGHUP (1) — 重新加载配置
killall nginx # 按进程名杀死
pkill -f "python app.py" # 按模式匹配杀死
常用信号
| 信号 | 编号 | 作用 |
|---|---|---|
| SIGHUP | 1 | 挂起 / 重载配置 |
| SIGINT | 2 | 中断(Ctrl+C) |
| SIGQUIT | 3 | 退出并 dump core |
| SIGKILL | 9 | 强制终止(不可捕获) |
| SIGTERM | 15 | 优雅终止(默认) |
| SIGSTOP | 19 | 暂停(不可捕获) |
| SIGCONT | 18 | 继续 |
10.3 前后台管理
# disown — 从 Shell 的作业表中移除(关闭终端不会终止)
long_running_command &
disown
# screen / tmux — 终端复用器(推荐)
tmux new -s mysession # 新建会话
tmux attach -t mysession # 重新连接
tmux ls # 列出会话
# Ctrl+B, D → 分离会话
11
系统服务 systemd
11.1 systemctl 命令
# 服务管理
systemctl start nginx # 启动
systemctl stop nginx # 停止
systemctl restart nginx # 重启
systemctl reload nginx # 重载配置(不中断服务)
systemctl status nginx # 查看状态
systemctl enable nginx # 开机自启
systemctl disable nginx # 取消开机自启
systemctl is-active nginx # 是否运行中
systemctl is-enabled nginx # 是否开机自启
systemctl mask nginx # 彻底禁用(连手动都不行)
systemctl unmask nginx # 取消禁用
# 查看所有服务
systemctl list-units --type=service # 运行中的
systemctl list-units --type=service --all # 所有(含未运行)
systemctl list-unit-files --type=service # 所有服务文件
# 系统操作
systemctl reboot # 重启
systemctl poweroff # 关机
11.2 编写 Unit 文件
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server --config /etc/myapp/config.yaml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
EnvironmentFile=-/etc/myapp/env
[Install]
WantedBy=multi-user.target
# 生效步骤
systemctl daemon-reload # 重新加载 unit 文件
systemctl enable --now myapp # 启用并立即启动
journalctl -u myapp -f # 查看日志
知识点 · Service Type
| Type | 含义 |
|---|---|
simple | 默认,主进程就是服务进程 |
forking | fork 到后台运行(需配合 PIDFile) |
oneshot | 一次性任务,执行完退出 |
notify | 类似 simple,但会通知 systemd 就绪 |
12
磁盘与存储
12.1 磁盘查看
lsblk # 块设备列表(树形)
lsblk -f # 含文件系统和UUID
fdisk -l # 分区表详情
blkid # 所有块设备的 UUID 和类型
df -h # 磁盘使用量(人类可读)
df -i # inode 使用量
du -sh /var/log/ # 目录大小
du -sh /var/log/* | sort -rh | head -10 # 找大目录
12.2 分区与格式化
# 分区(交互式)
fdisk /dev/sdb # MBR 分区
gdisk /dev/sdb # GPT 分区
parted /dev/sdb # 通用分区工具
# 格式化
mkfs.ext4 /dev/sdb1 # 格式化为 ext4
mkfs.xfs /dev/sdb1 # 格式化为 xfs
# 挂载
mount /dev/sdb1 /mnt/data # 临时挂载
umount /mnt/data # 卸载
mount -o ro /dev/sdb1 /mnt/data # 只读挂载
# 永久挂载 /etc/fstab
# UUID=xxx /mnt/data ext4 defaults 0 2
# /etc/fstab 格式
# 设备 挂载点 文件系统 选项 dump fsck顺序
易错点 · /etc/fstab 错误导致无法启动
修改 fstab 后务必执行 mount -a 测试。fstab 中的错误会导致系统无法启动。建议用 UUID 而非设备名(/dev/sdb1 可能在重启后变化)。
# 查看 UUID
blkid /dev/sdb1
# /etc/fstab 推荐写法
UUID=xxxx-xxxx /mnt/data ext4 defaults,noatime 0 2
13
内存与性能
13.1 内存查看
free -h # 内存使用情况
cat /proc/meminfo # 详细内存信息
# free -h 输出解读:
# total used free shared buff/cache available
# Mem: 15Gi 5.2Gi 1.0Gi 256Mi 9.1Gi 9.5Gi
# ↑ 重点关注 available 而非 free!
# buff/cache 是缓存,可被回收
易错点 · free 中的 "空闲内存"
free 列很少不代表内存不足。Linux 会积极使用空闲内存做磁盘缓存(buff/cache),available 列才是实际可用内存。缓存可以随时被回收,不影响应用。
13.2 性能监控工具
| 工具 | 用途 |
|---|---|
top / htop | 实时 CPU/内存监控 |
vmstat 1 | CPU、内存、IO、上下文切换 |
iostat -xz 1 | 磁盘 IO 详情 |
sar | 历史性能数据 |
iotop | 进程级 IO 监控 |
nmon | 综合性能监控 |
strace | 系统调用追踪 |
lsof | 打开的文件/连接 |
13.3 交换空间 (Swap)
# 查看 swap
swapon --show
free -h
# 创建 swap 文件
fallocate -l 2G /swapfile # 分配 2G
chmod 600 /swapfile # 修改权限
mkswap /swapfile # 格式化
swapon /swapfile # 启用
# 永久生效(添加到 /etc/fstab)
# /swapfile none swap sw 0 0
# 调整 swappiness(0~100,越低越不倾向用 swap)
sysctl vm.swappiness=10
# 永久:写入 /etc/sysctl.d/99-swap.conf
14
定时任务 cron
14.1 crontab 语法
# 编辑当前用户的 cron
crontab -e
# 查看
crontab -l
# cron 表达式格式
# ┌───────── 分钟 (0-59)
# │ ┌─────── 小时 (0-23)
# │ │ ┌───── 日 (1-31)
# │ │ │ ┌─── 月 (1-12)
# │ │ │ │ ┌─ 星期 (0-7, 0和7都是周日)
# │ │ │ │ │
# * * * * * command
# 示例
0 2 * * * /backup.sh # 每天凌晨2点
*/5 * * * * /check.sh # 每5分钟
0 9 * * 1 /weekly.sh # 每周一9点
0 0 1 * * /monthly.sh # 每月1号0点
30 18 * * 1-5 /workday.sh # 工作日18:30
# 特殊字符串
@reboot /startup.sh # 开机时
@daily /daily.sh # 等同于 0 0 * * *
@hourly /hourly.sh # 等同于 0 * * * *
易错点 · cron 环境变量
cron 的环境变量极简(PATH 可能只有 /usr/bin:/bin),脚本中必须使用绝对路径,否则命令找不到。
# 错误
0 2 * * * backup.sh
# 正确
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# 或者在 crontab 顶部设置 PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15
网络管理
15.1 网络配置
# 查看网络
ip addr # IP 地址(推荐)
ip route # 路由表
ip link # 网卡状态
ifconfig # 旧命令(已弃用)
ss -tulnp # 监听端口(推荐)
netstat -tulnp # 监听端口(旧)
cat /etc/resolv.conf # DNS 配置
hostname -I # 本机 IP
# 网络配置文件
# CentOS/RHEL: /etc/sysconfig/network-scripts/ifcfg-eth0
# Ubuntu/Debian: /etc/netplan/*.yaml (Netplan)
# /etc/network/interfaces (旧版)
15.2 网络诊断
ping -c 4 google.com # 测试连通性
traceroute google.com # 路由追踪
mtr google.com # 实时路由追踪(ping + traceroute)
nslookup example.com # DNS 查询
dig example.com # DNS 详细查询(推荐)
dig +short example.com # 简短输出
dig @8.8.8.8 example.com # 指定 DNS 服务器
# 连通性测试
curl -I https://example.com # HTTP 头部
curl -v https://example.com # 详细连接信息
wget https://example.com/file # 下载文件
# 端口测试
nc -zv host 80 # 测试端口连通性
nc -zv host 22 80 443 # 测试多个端口
telnet host 80 # 交互式连接
15.3 防火墙 (firewalld)
# firewalld (CentOS 7+)
firewall-cmd --state # 查看状态
firewall-cmd --list-all # 列出规则
firewall-cmd --add-service=http --permanent # 开放 HTTP
firewall-cmd --add-port=8080/tcp --permanent # 开放端口
firewall-cmd --reload # 重载规则
# iptables (更底层)
iptables -L -n # 查看规则
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 允许 SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 允许 HTTP
iptables -A INPUT -j DROP # 拒绝其他
iptables-save > /etc/iptables.rules # 保存规则
16
SSH 远程管理
16.1 SSH 基础
ssh user@host # 连接远程主机
ssh -p 2222 user@host # 指定端口
ssh user@host "ls -la /var/log" # 执行远程命令
# 文件传输
scp file.txt user@host:/path/ # 上传
scp user@host:/path/file.txt . # 下载
scp -r dir/ user@host:/path/ # 递归传输目录
rsync -avz -e ssh src/ user@host:/dest/ # 增量同步(推荐)
16.2 SSH 密钥认证
# 生成密钥对
ssh-keygen -t ed25519 -C "your@email.com"
# 生成在 ~/.ssh/id_ed25519 (私钥) 和 ~/.ssh/id_ed25519.pub (公钥)
# 上传公钥到服务器
ssh-copy-id user@host
# 配置免密登录 ~/.ssh/config
Host myserver
HostName 192.168.1.100
User admin
Port 2222
IdentityFile ~/.ssh/id_ed25519
# 然后直接:ssh myserver
安全要点
- 私钥权限必须是
600:chmod 600 ~/.ssh/id_ed25519 .ssh目录权限必须是700:chmod 700 ~/.ssh- 生产环境应禁用密码登录:
PasswordAuthentication no - 修改默认端口 22 为其他端口可减少扫描攻击
- 推荐使用
ed25519密钥(比 RSA 更安全更短)
16.3 SSH 隧道
# 本地端口转发(访问本地 8080 → 远程 80)
ssh -L 8080:localhost:80 user@host
# 远程端口转发(远程 9090 → 本地 3000)
ssh -R 9090:localhost:3000 user@host
# 动态端口转发(SOCKS 代理)
ssh -D 1080 user@host
# 跳板机(ProxyJump)
ssh -J jumpuser@jumphost admin@target
17
防火墙与安全
17.1 安全加固清单
# 1. 禁用 root SSH 登录
# /etc/ssh/sshd_config
PermitRootLogin no
# 2. 仅允许密钥认证
PasswordAuthentication no
# 3. 安装 fail2ban(防暴力破解)
apt install fail2ban # Debian/Ubuntu
yum install fail2ban # CentOS
systemctl enable fail2ban
# 4. 定期更新系统
apt update && apt upgrade # Debian/Ubuntu
yum update # CentOS
# 5. 最小权限原则
# 不用 root 运行应用,创建专用用户
# 6. 关闭不需要的服务
systemctl disable --now telnet
systemctl disable --now ftp
17.2 SELinux / AppArmor
# SELinux (CentOS/RHEL)
getenforce # 查看模式: Enforcing/Permissive/Disabled
setenforce 0 # 临时切换为 Permissive
semanage port -l | grep http # 查看端口标签
restorecon -Rv /var/www/ # 恢复文件安全上下文
# AppArmor (Ubuntu/Debian)
aa-status # 查看状态
aa-enforce /etc/apparmor.d/profile # 启用配置
难点 · SELinux 导致服务异常
很多运维新手遇到"配置正确但服务不工作"的问题,往往是因为 SELinux 阻止了访问。快速排查:
# 检查 SELinux 是否阻止
ausearch -m avc -ts recent
cat /var/log/audit/audit.log | grep denied
# 如果确认是 SELinux,正确做法是添加策略,而非直接禁用
setsebool -P httpd_can_network_connect on
18
日志管理
18.1 重要日志文件
| 日志文件 | 内容 |
|---|---|
/var/log/syslog | 系统日志(Debian/Ubuntu) |
/var/log/messages | 系统日志(CentOS/RHEL) |
/var/log/auth.log | 认证日志(Debian/Ubuntu) |
/var/log/secure | 认证日志(CentOS/RHEL) |
/var/log/kern.log | 内核日志 |
/var/log/dmesg | 硬件/驱动日志 |
/var/log/nginx/ | Nginx 日志 |
/var/log/cron | 定时任务日志 |
18.2 journalctl (systemd)
journalctl -xe # 最近日志(含解释)
journalctl -u nginx # 指定服务的日志
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2024-01-15" --until "2024-01-16"
journalctl -f # 实时跟踪(类似 tail -f)
journalctl -p err # 只看错误级别
journalctl --disk-usage # 日志占用空间
journalctl --vacuum-size=500M # 清理到 500M
18.3 logrotate
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily # 每天轮转
missingok # 文件不存在不报错
rotate 30 # 保留30份
compress # gzip 压缩
delaycompress # 延迟一次压缩
notifempty # 空文件不轮转
create 644 root root # 新文件权限
postrotate
systemctl reload myapp
endscript
}
# 手动测试
logrotate -d /etc/logrotate.d/myapp # 调试模式
logrotate -f /etc/logrotate.d/myapp # 强制执行
19
包管理
19.1 Debian/Ubuntu (apt)
apt update # 更新包索引(必须先执行!)
apt upgrade # 升级所有包
apt install nginx # 安装
apt remove nginx # 删除(保留配置)
apt purge nginx # 完全删除(含配置)
apt autoremove # 清理不需要的依赖
apt search nginx # 搜索
apt show nginx # 包信息
apt list --installed # 已安装的包
dpkg -l # 已安装的包(底层)
dpkg -L nginx # 包含的文件
dpkg -S /usr/bin/nginx # 属于哪个包
19.2 RHEL/CentOS (yum/dnf)
yum update # 更新
yum install nginx # 安装
yum remove nginx # 删除
yum search nginx # 搜索
yum info nginx # 信息
yum list installed # 已安装
yum provides /usr/bin/nginx # 查找文件所属包
yum history # 操作历史
yum history undo 42 # 撤销第42次操作
# CentOS 8+ / Fedora 用 dnf 替代 yum
dnf install nginx
20
LVM 与 RAID
20.1 LVM(逻辑卷管理)
# LVM 层次:物理卷(PV) → 卷组(VG) → 逻辑卷(LV)
# 创建
pvcreate /dev/sdb /dev/sdc # 创建物理卷
vgcreate data_vg /dev/sdb /dev/sdc # 创建卷组
lvcreate -L 50G -n app_lv data_vg # 创建逻辑卷(固定大小)
lvcreate -l 100%FREE -n app_lv data_vg # 使用所有空间
# 格式化和挂载
mkfs.ext4 /dev/data_vg/app_lv
mount /dev/data_vg/app_lv /app
# 扩容(LVM 最大优势!)
lvextend -L +20G /dev/data_vg/app_lv # 扩大 20G
resize2fs /dev/data_vg/app_lv # ext4 扩容文件系统
xfs_growfs /app # xfs 扩容文件系统
# 查看
pvdisplay, vgdisplay, lvdisplay
pvs, vgs, lvs # 简洁视图
知识点 · LVM 快照
# 创建快照(用于备份,几乎瞬间完成)
lvcreate -L 5G -s -n app_snap /dev/data_vg/app_lv
mount /dev/data_vg/app_snap /mnt/snapshot
# 备份完成后删除快照
lvremove /dev/data_vg/app_snap
21
内核与模块
21.1 内核参数调优
# 查看内核参数
sysctl -a # 所有参数
sysctl net.ipv4.ip_forward # 查看单个参数
# 临时修改
sysctl -w net.ipv4.ip_forward=1
# 永久修改 → /etc/sysctl.d/99-custom.conf
net.ipv4.ip_forward = 1
net.core.somaxconn = 65535
vm.swappiness = 10
fs.file-max = 655350
# 使配置生效
sysctl --system # 加载所有配置文件
# 查看内核版本
uname -r # 内核版本
uname -a # 全部信息
21.2 内核模块
lsmod # 已加载模块
modprobe module_name # 加载模块
modprobe -r module_name # 卸载模块
modinfo module_name # 模块信息
22
Docker 容器
22.1 Docker 基础命令
# 镜像操作
docker pull nginx:1.24 # 拉取镜像
docker images # 列出镜像
docker rmi nginx:1.24 # 删除镜像
docker image prune # 清理无用镜像
# 容器操作
docker run -d -p 80:80 --name web nginx # 后台运行,映射端口
docker run -it ubuntu bash # 交互式运行
docker ps # 运行中的容器
docker ps -a # 所有容器(含停止的)
docker stop web # 停止
docker start web # 启动
docker restart web # 重启
docker rm web # 删除容器
docker exec -it web bash # 进入容器
docker logs -f web # 查看日志
docker inspect web # 详细信息
docker stats # 资源监控
# 清理
docker system prune -a # 清理所有无用资源
22.2 Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
# 构建
docker build -t myapp:latest .
# Docker Compose
docker compose up -d # 后台启动所有服务
docker compose down # 停止并删除
docker compose logs -f # 查看日志
23
故障排查
23.1 系统排查流程
# 1. 系统整体状态
uptime # 负载均值(1/5/15分钟)
# 理想值 < CPU 核数
free -h # 内存
df -h # 磁盘
iostat -xz 1 # IO
# 2. CPU 排查
top -c # 按 CPU 排序,找高消耗进程
pidstat -u 1 # 每秒进程 CPU
perf top # CPU 热点函数
# 3. 内存排查
ps aux --sort=-%mem | head -20 # 内存 Top 20
slabtop # 内核 slab 缓存
cat /proc/meminfo # 详细内存信息
# 4. 磁盘排查
iotop # IO Top
lsof +D /var/log/ # 谁在用这个目录
fuser -v /mnt/data # 谁在用这个挂载点
# 5. 网络排查
ss -s # 连接统计
ss -tnp # TCP 连接详情
tcpdump -i eth0 port 80 # 抓包
23.2 常见问题速查
| 症状 | 排查命令 | 常见原因 |
|---|---|---|
| 系统很卡 | top, vmstat 1 | CPU 满载、内存不足、IO 瓶颈 |
| 磁盘满 | df -h, du -sh /* | 日志爆满、大文件、inode 耗尽 |
| 服务无法启动 | systemctl status, journalctl -xe | 配置错误、端口占用、权限 |
| 无法远程连接 | ss -tlnp, iptables -L | 防火墙、SSH 配置、网络不通 |
| OOM Killed | dmesg | grep oom | 内存不足被内核杀死 |
| 僵尸进程 | ps aux | grep Z | 父进程未回收子进程 |
23.3 strace 系统调用追踪
# 追踪命令的系统调用
strace ls /tmp # 追踪 ls 命令
strace -p 1234 # 追踪运行中的进程
strace -e open,read -p 1234 # 只追踪 open 和 read
strace -c ls /tmp # 统计系统调用
strace -f -p 1234 # 追踪子进程
24
易错点速查表
命令行陷阱
| # | 易错点 | 正确做法 |
|---|---|---|
| 1 | rm -rf / 或 rm -rf ~ | 永远不要执行;用 trash-put |
| 2 | chmod 777 生产目录 | 最小权限原则:755 / 644 |
| 3 | usermod -G 覆盖附加组 | 必须用 usermod -aG |
| 4 | 变量赋值有空格 a = 1 | a=1(无空格) |
| 5 | [ $a = $b ] 变量为空 | [ "$a" = "$b" ](双引号) |
| 6 | 2>&1 顺序错误 | cmd > file 2>&1(在后面) |
| 7 | fstab 写错无法启动 | 修改后 mount -a 测试 |
| 8 | cron 里用相对路径 | 全部用绝对路径 |
| 9 | 看 free 的 free 列 | 看 available 列 |
| 10 | kill -9 作为首选 | 先 kill(SIGTERM),不行再 -9 |
| 11 | 用 ifconfig | 用 ip addr(ifconfig 已弃用) |
| 12 | sed -i 无备份 | sed -i.bak(先备份) |
| 13 | find + xargs 文件名有空格 | -print0 | xargs -0 |
| 14 | SELinux 禁用了事 | 添加正确的 SELinux 策略 |
| 15 | root 运行应用 | 创建专用用户 |
经典坑 · 磁盘满排查
# 现象:df -h 显示磁盘满,但 du -sh /* 加起来不够
# 原因:已删除文件仍被进程持有(文件句柄未释放)
# 排查
lsof | grep deleted # 查找已删除但未释放的文件
# 解决:重启占用进程
systemctl restart nginx # 释放文件句柄
# 不重启释放(不推荐)
echo > /proc/PID/fd/FD_NUMBER # 清空文件描述符
经典坑 · 端口被占用
# 错误信息:bind: address already in use
# 找到占用端口的进程
ss -tlnp | grep :80
lsof -i :80
# 杀掉进程
kill PID
# 或者允许端口快速复用(开发环境)
sysctl -w net.ipv4.tcp_tw_reuse=1
Linux系统操作黄金法则
- 先备份再操作 — 修改配置前
cp file file.bak - 先测试再应用 — 用
mount -a、nginx -t、visudo -c - 用最小权限 — 不用 root 跑服务,不给 777
- 先 kill 再 kill -9 — 给进程优雅退出的机会
- 看日志 — 80% 的问题能在日志中找到答案
- 用 tmux/screen — 防止 SSH 断开导致操作中断
- 自动化 — 能写脚本就不手动操作
- 监控先行 — 出问题前就知道