简介:《linux实战100例》面向Linux初学者、初中级运维与开发人员,聚焦日常命令使用、服务配置和故障排查,帮助读者通过典型案例建立从操作到定位问题的完整思路。包内共204个文件,以195个HTML技术文档为主体,辅以PDF、DOC说明及少量压缩包和可执行文件,整体约40.19MB,目录配有索引页,便于按主题或关键字检索。内容强调功能调用过程,收录100个较有代表性的实例,涉及网络调用命令、Apache参数配置详解、Linux错误代码解释,以及编译选项、内置函数、告警与优化设置等文档主题,并整理应用过程中常见错误的解决方法,适合对照实验场景理解参数含义和排错路径。已有2180人学习,可作为实践练习、知识补漏与故障排查的参考材料。
1. 从一台“不敢重启”的机器说起
接手一台别人维护过的机器,最怕的不是命令不会敲,而是不知道从哪一步开始:服务起不来、日志不知道落在哪、磁盘告警却找不到是谁写的,一通ls和cat之后仍然没有证据链。linux 实战100例这份资源针对的就是这个场景——它把 100 个可独立执行的小案例按能力分层排好,从文件权限、文本统计一路到进程排查、服务托管和定时任务,每个例子都能在十分钟内跑完并看到明确输出。它适合三类人:要交课程设计或毕业设计的在校生,需要一份能演示、能讲清原理的功能清单;刚转到 Linux 相关岗位的开发者,缺一套系统性的上手练习;以及要给团队做内部培训的负责人,想直接拿现成案例改成自己的教材。下面按需求定位、结构设计、模块实现、验收答辩四段,把它拆成一份可以照着做的完整方案。
2. 案例集的能力分层:四层结构与单例四段式模板
100 个案例堆在一起,最大的风险不是难度,而是顺序错乱——先做服务托管再做文件权限,遇到问题连日志都找不到。我一般先把它们按“用得上”的顺序分层,再给每个案例套一个固定模板,保证做完一遍能留下可复用的东西,而不是一堆敲过就忘的命令。
2.1 四层能力模型与案例配比
分层依据是排障时的真实调用顺序:先能定位文件,再能看懂内容,然后才能观察进程和网络,最后才是把手工操作固化成服务与脚本。按这个逻辑,100 例大致落在四层里,配比可以按下面的表来分配,如果你手上的案例集结构略有出入,按能力归位即可,不必强行凑数。
| 层级 | 覆盖能力 | 建议案例数 | 典型场景 |
|---|---|---|---|
| L1 命令基础 | 文件定位、权限、文本处理、压缩归档 | 35 | 找出三天内改动过的配置、统计访问日志 Top IP |
| L2 观测排障 | 进程、端口、磁盘、内存、日志 | 30 | 端口被占用、磁盘写满、服务反复重启 |
| L3 服务托管 | 用户与 sudo、软件包、systemd 单元 | 20 | 把脚本变成开机自启的常驻服务 |
| L4 自动化 | shell 脚本、cron、备份与清理策略 | 15 | 每日备份、日志轮转、失败重试 |
这个配比不是拍脑袋。L1 和 L2 占了六成以上,因为实际工作里九成时间花在“找证据”上;L3、L4 案例少但单个耗时长,属于必须动手做一遍才能记住的部分。学生在课设里最容易犯的错是把 L4 写得很花哨,而 L1 的命令全靠复制粘贴,答辩时一问参数含义就露馅。
提示:分层之后建议给每层单独建目录,案例脚本命名带层级前缀,后面写自检脚本时可以直接按前缀批量跑。
2.2 单个案例的四段式模板
每个案例都按“场景一句话、最小命令、验证输出、清理回滚”四段来写。这个模板的价值在于第四段——绝大多数教程只教你敲命令,不教你收尾,结果练习环境越跑越脏,第二次做的时候现象对不上,直接卡死。下面是一个按模板写出来的完整案例,可以直接作为其他案例的骨架。
#!/usr/bin/env bash # 案例 L1-07:找出 7 天内被修改过的配置文件 # 场景:怀疑有人改过配置但不确定改了哪个 # 1) 最小命令:只在 /etc 下找,-xdev 避免跨挂载点扫到别的盘 find /etc -xdev -type f -name "*.conf" -mtime -7 -print # 2) 验证:统计条数,条数为 0 说明近期没人动过配置文件 find /etc -xdev -type f -name "*.conf" -mtime -7 -print | wc -l # 3) 回滚/清理:本案例只读,不产生副作用,无需清理-xdev的作用是不跨越文件系统边界,扫/etc时不会顺着一堆挂载点跑到数据盘上去,在容器和云主机上这个参数能省掉大量等待。-mtime -7的-表示“7 天以内”,写成+7就变成“7 天以前”,这两个符号搞反是新手最常犯的错误之一。-print是默认动作,写出来是为了让脚本读起来意图明确,方便别人接手。
四段模板里,第二段“验证输出”是最容易被跳过、也最不能跳过的部分。我的做法是要求每个案例都给出一个可判断的数值或行数,比如“条数为 0”“输出三行”“返回码为 1”。没有可判断的输出,就等于没有验收标准,做完也不知道对不对。
2.3 练习环境的准备与快照
这套案例涉及删除文件、占满磁盘、改坏服务配置这类破坏性操作,直接在主力机器上跑迟早出问题。通常的做法是准备一台可以随时重建的练习机,或者用容器跑一个带 systemd 的完整环境。练习目录建议统一放在/srv/lab,配一个专用账号,所有破坏性操作都限制在这个账号和目录下。
# 建练习账号与目录,后续所有案例都在这个沙箱里做 useradd -m -s /bin/bash sandbox mkdir -p /srv/lab/{data,logs,backup,cases} chown -R sandbox:sandbox /srv/lab # 建一个 200M 的小文件系统,专门用来练"磁盘写满"类案例 dd if=/dev/zero of=/srv/lab/disk.img bs=1M count=200 mkfs.ext4 /srv/lab/disk.img mkdir -p /srv/lab/mnt && mount -o loop /srv/lab/disk.img /srv/lab/mnt用一个镜像文件挂成独立分区,好处是练“磁盘满”“inode 耗尽”这类案例时不会波及真实根分区,出问题直接umount删掉重来。做完一轮之后给练习机打一个快照,后面重跑案例从快照恢复,比手工清理残留文件可靠得多。这一步看着麻烦,但它是整套案例能反复练的前提,跳过它后面全是血泪经验。
3. 文件、文本与权限:把重复排查沉淀成命令
L1 层的案例看起来简单,实际最容易写成了“命令手册摘抄”。判断一个案例有没有价值,标准是:下次遇到同类问题,你能不能不看笔记直接敲出来。要做到这一点,案例必须围绕具体场景组合参数,而不是孤立地罗列选项。
3.1 权限与文件定位的高频组合
权限相关的问题在排查里占比很高,典型现象是“服务以某个账号启动,但读不到自己的配置文件”。这类问题的定位路径固定:先看文件属主和权限位,再看目录的执行权限,最后看 ACL 和 SELinux 上下文。案例集里应该把这条路径拆成几个独立小例,每个都能单独验证。
# 找出系统中所有带 SUID 位的可执行文件,用来核查异常提权风险 find / -xdev -perm -4000 -type f -exec ls -l {} \; 2>/dev/null # 查看某个目录的 ACL 规则,普通 ls -l 看不到 + 号背后的内容 getfacl -p /srv/lab/data # 检查服务账号能否真正进入目录并读取文件(比看权限位更直接) sudo -u sandbox test -r /srv/lab/data/app.conf && echo "可读" || echo "不可读"-perm -4000里的-是“至少包含这些位”的意思,漏掉它会把权限位不完全匹配的文件过滤掉。getfacl那一条经常被忽略:ls -l输出末尾的+只告诉你“有额外 ACL”,具体规则得靠getfacl看。第三条用sudo -u实际切到目标账号去测,比人工推理权限位可靠得多,尤其是目录上缺少x位导致“文件可读但进不去”的情况,肉眼很难看出来。
目录权限里最反直觉的一条是:目录的r决定能不能列文件名,x决定能不能进入和访问里面的文件。只有r没有x,你能看到文件名但读不到内容;只有x没有r,你知道路径能进去但列不出目录。这个点在答辩时被问到的概率很高,案例里最好专门设计一个对比实验。
3.2 文本处理的实战配方
文本处理是 L1 层最值得投入的部分,因为日志分析、配置比对、批量改文件都靠它。案例不要写成awk语法讲解,而要写成“给定一份日志,输出 Top 10 来源 IP 和状态码分布”这样的成品命令,每个都带注释。
# 场景:从 Nginx 访问日志里统计请求量最高的 10 个来源 IP # $1 默认是访问日志的第一列(客户端地址),先排序再计数再倒序取前 10 LC_ALL=C awk '{print $1}' /srv/lab/logs/access.log \ | LC_ALL=C sort \ | LC_ALL=C uniq -c \ | LC_ALL=C sort -rn \ | head -n 10 # 场景:统计各 HTTP 状态码出现次数,$9 是状态码所在列 awk '{count[$9]++} END {for (c in count) print c, count[c]}' /srv/lab/logs/access.log \ | sort -k2 -rnLC_ALL=C不是可有可无的装饰:默认 locale 下sort按本地化规则比较字符串,速度和结果都可能和预期不同,日志这种纯 ASCII 内容用 C locale 既快又稳定。第二个例子用 awk 的关联数组一次遍历完成计数,比“先 grep 再 wc -l”循环十次的写法快一个数量级,日志上百万行时差别非常明显。
sort | uniq -c这个组合有一个前提:uniq只能合并相邻的重复行,所以必须先sort。很多人在管道里漏掉排序,结果统计出来的计数全是 1,还以为命令写错了。案例里把这个坑明确写出来,比讲十遍uniq的参数有用。
3.3 把常用组合封装成小工具
单个案例跑通只是第一步,真正省时间的是把高频组合封装成带参数的脚本,放进~/bin或/usr/local/bin。这一步做完,L1 层的案例就从“练习”变成了“资产”。
#!/usr/bin/env bash # topn.sh:统计日志中指定字段的 Top N,默认取第 1 列 # 用法:topn.sh <日志文件> [字段序号] [条数] set -euo pipefail LOG="${1:?请提供日志文件路径}" FIELD="${2:-1}" N="${3:-10}" awk -v f="$FIELD" '{print $f}' "$LOG" \ | LC_ALL=C sort | LC_ALL=C uniq -c | LC_ALL=C sort -rn | head -n "$N"set -euo pipefail这三件套建议在所有自写脚本里固定加上:-e让命令失败即退出,-u让引用未定义变量报错,pipefail让管道中任意一段失败都能被捕获——默认情况下管道只看最后一条命令的返回码,前面awk挂了也可能返回成功,这是排查时最隐蔽的黑匣子。${1:?}的写法在参数缺失时直接报错退出,比运行到一半才失败更好定位。
脚本写好后建议加一条使用示例注释,一两个月后回来看,注释比记忆可靠。同类脚本攒到十几个,可以再写一个--help分支统一输出用法,答辩演示时打开这个帮助信息,比现场敲命令更能说明工程完整度。
4. 排障与服务化落地:从证据链到常驻服务
L2 到 L4 的案例是整套资源里区分度最高的部分。命令层的案例照着敲基本都能过,而排障和服务托管涉及多组件协同,一旦环境有细微差异就会翻车,也正是在这部分,案例设计的质量差距最明显。
4.1 进程与端口:按顺序收集证据
端口被占用、进程莫名消失、CPU 飙高,这三类问题的排查顺序是固定的:先看进程在不在,再看它监听了什么,最后看它占了多少资源。案例应该把这个顺序固化成一组命令,而不是让学习者自己去猜先敲哪个。
# 1) 按 CPU 排序看前 10 个进程,确认是否有明显异常进程 ps aux --sort=-%cpu | head -n 11 # 2) 查看所有监听端口及对应进程(需要 root 才能看到别人的进程名) ss -lntp # 3) 只看某个端口被谁占了,比 ss 全量输出更好定位 ss -lntp 'sport = :8080' # 4) 进程状态异常时看它的父子关系和启动时间,判断是不是被反复拉起 ps -eo pid,ppid,stat,etime,cmd --sort=start_time | tail -n 20ss已经基本取代netstat,在较新的系统上netstat可能根本没装。sport = :8080这种过滤语法比grep 8080准确,因为 grep 会把对端端口、PID 里含 8080 的行一起匹配进来。ps的stat列值得单独讲:Z是僵尸进程,D是不可中断睡眠(通常在等 IO),S是睡眠,R是运行——看到D状态堆积,基本可以直接转向磁盘 IO 排查,不用再在进程上浪费时间。
关于僵尸进程有一点要说清楚:僵尸本身不占 CPU 和内存,杀它没有意义,因为进程已经退出了,只是父进程没回收。正确的做法是找到它的父进程并处理父进程的wait逻辑,或者重启父进程。案例里如果只写“kill -9 僵尸进程”,是彻头彻尾的错误示范。
4.2 磁盘与 IO:区分“空间满”和“看不到的空间”
磁盘告警的案例必须覆盖三种情况,缺一种就会在实际排查中卡住:分区真的写满了、inode 用完了、以及文件已删除但句柄没释放。这三种现象在df -h上表现可能完全一样,处理方式却完全不同。
# 看空间使用率,先确认是哪一层的问题 df -h # 看 inode 使用率,小文件多的场景(缓存、邮件队列)经常是这项满了 df -i # 从根目录逐层找大目录,-x 不跨挂载点,--max-depth 控制展开层数 du -x -h --max-depth=1 / 2>/dev/null | sort -h | tail -n 10 # 找已删除但仍被进程占用的文件:df 显示满但 du 统计不出来时用这条 lsof +L1 2>/dev/null | head -n 20df显示 100% 而du加起来只有一半,最常见的原因就是有大文件被删除但进程还开着句柄,空间要等进程关闭或重启才释放。lsof +L1专门列link count小于 1 的已打开文件,找到对应 PID 后重启服务即可回收。另一种情况是挂载点被覆盖:往一个目录里写了大量数据,之后又把新分区挂到该目录上,原来的数据仍占着根分区但du看不到,mount配合df对照能发现。
IO 层面用iostat -x 1看%util和await,%util长期接近 100% 说明设备饱和,await高说明排队严重。这里有个容易误判的点:机械盘和网络存储在高并发下%util天然容易打满,不能只凭这一项就断定有故障,要结合业务侧的响应时间一起看。
4.3 systemd 托管:把脚本变成可靠服务
L3 层最有代表性的案例是“把一个手工执行的脚本变成开机自启、崩溃自动重启的服务”。这件事看着简单,但Type、ExecStart前台运行、WorkingDirectory这三处只要错一处,服务就会启动即退出,systemctl status只给一句含糊的失败信息。
[Unit] Description=Lab Demo Collector After=network-online.target Wants=network-online.target [Service] Type=simple User=sandbox WorkingDirectory=/srv/lab/app Environment="LANG=C.UTF-8" ExecStart=/usr/bin/python3 /srv/lab/app/main.py Restart=on-failure RestartSec=3 StandardOutput=journal StandardError=journal LimitNOFILE=65535 [Install] WantedBy=multi-user.targetType=simple要求ExecStart指向的程序在前台持续运行;如果脚本内部把真正干活的进程丢到后台自己退出了,systemd 会认为服务已结束,于是要么显示inactive (dead),要么按Restart策略反复拉起。这是服务托管第一号翻车点。WorkingDirectory决定相对路径的基准,脚本里写./config.yaml而没配这一项,工作目录会变成/,配置直接读不到。LimitNOFILE在文件句柄密集型服务里必须显式设置,默认值在高并发下很容易触顶。
改完单元文件之后要走一遍systemctl daemon-reload,否则 systemd 用的还是旧配置。验证方式不要只看systemctl status,用journalctl -u 服务名 --since "5 min ago" -f跟一段日志,确认它真的在持续输出,才算托管成功。
4.4 定时任务与脚本工程化
cron 案例的翻车率比 systemd 还高,原因是 cron 的执行环境和登录 shell 完全不同:PATH 更短、没有别名、没有用户级环境变量。同样的脚本手工跑正常,放进 crontab 就静默失败,排查时连日志都没有。
# 每分钟执行一次采集脚本 # 要点:用绝对路径调用解释器和 flock,重定向同时接住 stdout 和 stderr * * * * * /usr/bin/flock -n /var/lock/collect.lock /srv/lab/bin/collect.sh >> /srv/lab/logs/collect.log 2>&1flock -n的作用是拿不到锁就立即退出,避免上一轮没跑完、下一轮又叠加进来,把机器拖垮——定时任务执行时间超过间隔时,这种堆积是必然发生的,只是早晚问题。重定向里的2>&1必须放在>>之后,顺序反了就接不住错误输出,日志里只剩正常信息,出错时一片空白。cron 的时间字段里%有特殊含义(表示换行),命令中如果真的需要百分号必须转义成\%,这个问题在写日期格式化时特别容易踩到。
脚本本身也要按工程化要求写:开头加set -euo pipefail,日志带时间戳,关键步骤有返回码检查,失败时输出足够定位的上下文。案例集里可以专门安排一个“故意失败”的案例,让学习者看到没有错误处理的脚本是怎么静默吃掉问题的,印象比看十遍规范文档都深。
5. 避坑排查:五类最容易翻车的现场
这一章不是知识补充,而是把上面各层里失败率最高的操作单独拎出来。每一条都按“现象、原因、解决”写,遇到时可以直接对照。
5.1 通配符与变量为空导致的误删
现象:执行一条清理命令后,目标目录之外的文件也没了。原因通常是rm -rf $DIR/*里DIR变量为空,命令实际展开成rm -rf /*;或者通配符没匹配到任何文件,某些写法下会退化成对当前目录的操作。解决办法是删除类脚本一律加两道保险:变量用${DIR:?}强制非空,删除前先ls打印一遍待删清单并让人确认。
# 安全写法:变量为空直接报错退出,且先打印再删 TARGET="${1:?请提供要清理的目录}" ls -ld "$TARGET" || exit 1 find "$TARGET" -xdev -type f -name "*.tmp" -mtime +7 -print -delete用find ... -delete代替通配符,好处是匹配规则明确、支持-print预览,还能用-xdev限定不跨挂载点。删除类案例在练习环境里跑,别在真实数据上试。
5.2 crontab 里命令不执行也不报错
现象:手工执行完全正常,写进 crontab 后没有任何输出和日志。原因几乎总是环境差异:PATH 里找不到命令、脚本里用了只在交互 shell 生效的别名、或者依赖了未导出的环境变量。解决办法是 crontab 中全部用绝对路径,脚本开头显式设置PATH,并且务必加输出重定向。
# 脚本头部显式固定 PATH 与工作目录,消除环境差异 export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin cd /srv/lab || exit 1排查阶段可以临时加一条* * * * * env > /tmp/cron.env,把 cron 的真实环境导出来和登录 shell 对比,差异一目了然。
5.3 服务启动即退出,状态信息含糊
现象:systemctl start后立刻变成failed或inactive (dead),status里只有一行退出码。原因多为Type与实际运行方式不匹配、ExecStart用了相对路径、或者程序把自身 daemon 化后父进程退出。解决办法是先手工以服务账号在前台跑一遍,确认程序本身没问题,再检查单元文件的Type、ExecStart、WorkingDirectory三项,最后用journalctl -u 服务名 -n 50看完整日志。
5.4 磁盘满了但 du 统计不出来
现象:df -h显示使用率 100%,du -sh逐层加起来远小于分区容量。原因有三种:已删除但被进程占用的文件、inode 耗尽、挂载点覆盖。解决办法按顺序排查:df -i看 inode,lsof +L1找已删除句柄,mount与df对照检查挂载点是否覆盖了原有目录。三种情况处理方式不同,先分清再动手,别急着删文件。
5.5 改完远程登录配置把自己锁在门外
现象:调整登录相关配置并重启服务后,新会话连不上,旧会话一断开就彻底失联。原因是配置语法错误、监听端口或地址变化、访问控制规则没同步放行。解决办法是改配置前先保留一个已登录会话不退出,改完用另一个终端验证新配置能正常登录,确认无误再关闭旧会话;同时准备一条带-p指定端口的备用连接命令。这个习惯在服务托管类案例里要当作硬性要求写进去,不是可选项。
6. 验收与答辩:怎么证明这 100 例真跑通了
案例集做完,最怕的是“看起来都做过,一问就说不清”。验收的核心不是数量,而是可复现性——换一台机器、换一个人,能不能在同样时间内得到同样的结果。我一般用下面这张表来判定这套案例是否真的落地。
| 验收维度 | 检查方式 | 合格线 |
|---|---|---|
| 完成率 | 自检脚本批量执行全部案例脚本 | 通过率不低于 90% |
| 环境可重建 | 从快照恢复后重跑一遍关键案例 | 全程无需手工修补 |
| 幂等性 | 同一脚本连续执行两次 | 第二次输出与第一次一致 |
| 排障可复现 | 随机抽 3 个 L2 案例现场演示 | 5 分钟内给出证据链 |
| 原理可讲清 | 抽 1 个案例解释每个参数 | 能说清为什么用这个参数 |
自检脚本本身也是交付物的一部分,写法不复杂但很能说明工程习惯:
#!/usr/bin/env bash # check.sh:批量执行案例脚本并统计通过率 # 约定:每个案例脚本正常退出返回 0,失败返回非 0 set -u PASS=0 FAIL=0 for f in /srv/lab/cases/*.sh; do if bash "$f" >/dev/null 2>&1; then PASS=$((PASS + 1)) else FAIL=$((FAIL + 1)) echo "FAIL: $f" fi done # 输出汇总,方便直接贴进验收记录 echo "通过 ${PASS} 条,失败 ${FAIL} 条"这里没有用set -e,因为需要让循环在单个案例失败时继续跑完,收集全部失败项而不是第一个错误就中断——验收脚本和业务脚本的容错要求正好相反,这一点在答辩时是可以主动讲出来的设计取舍。
答辩环节真正拉开差距的是“为什么”而不是“是什么”。同样一个find案例,能说出-xdev是为了不跨挂载点、-mtime -7的符号方向、-print为什么显式写出,和只会背命令,评分完全不是一档。准备时建议从四层里各挑一个案例,把“如果参数改成另一个值会发生什么”提前想清楚,这类追问几乎必问。
注意:演示前务必在干净快照上重跑一遍,别用几天前跑通过的环境直接上场,残留状态导致的失败在现场很难解释清楚。
从那以后我每次带人过这类案例集,都强制要求先跑一遍自检脚本、再讲原理,顺序反了就一定有人拿“我这能跑”当挡箭牌。先有可复现的证据,再谈理解,这套顺序放到任何项目验收里都成立。希望帮到你。
本文还有配套的精品资源,点击获取