☰
Linux实战100例:可复现的命令与故障排查案例集
2026/11/2 2:03:39 网站建设 项目流程

简介:面向 Linux 初学者与运维实战进阶者的《linux实战100例》资料包,围绕 100 个经典代表性的实例组织内容,涵盖网络调用命令、Apache 参数配置详解、Linux 错误代码解析,以及应用过程中常见报错的排查与解决方法,兼顾命令实操与配置调优两个层面。压缩包共 204 个文件,约 40.19MB,以 195 个 html 页面为主体,构成可按索引页与关键词页双向检索的示例集合;另含 3 个 pdf 与 1 个 doc 供整体阅读归档,2 个 zip、2 个 rar 子包及 1 个 exe 多为配套素材与自述材料,便于按功能快速定位实例。目前已有 2180 人学习下载。读者可从中获得可直接对照执行的命令样例、Apache 核心参数的含义与配置思路、错误码到成因的对应关系,以及一条从出错现象回溯到配置项的排错路径,适合边练边查。

1. 装完系统之后的那段空白:linux 实战100例 要解决的到底是什么

装好系统、换好软件源、能远程登录,然后就卡住了——这是我见过最普遍的状态:命令的语法背了一堆,真给一台机器却不知道该敲什么。linux 实战100例这份案例集针对的就是这段空白,它不按命令手册的字母顺序排,而是按“一个开发或运维每天真正会遇到的事”排:文件找不到、磁盘写不进去、端口不通、服务起不来、定时任务到点没执行、日志刷屏看不出重点。适合三类人:刚学完基础命令想找活干的学生,要交一份完整课设或毕设的同学,以及平时写业务代码、偶尔得上机器查问题的后端开发。它不讲 Linux 是什么,它给 100 个能当场复现的小场景,每个场景都带一句可验证的结果,跑没跑通自己就能判断,不用等谁批改。

2. 案例集的分层设计:八个模块、四级台阶与 100 个案例的配额

一百个案例最怕的是“一百条命令罗列”,看着满,用起来一个都想不起来。所以这份案例集在动手写第一个案例之前,先定了两件事:难度怎么分层、模块怎么配额。分层决定读者从哪进、往哪走;配额决定这一百个位置分给谁,避免某个模块塞了三十个案例、另一个模块只有三个凑数。做过完整方案的人都知道,目录结构定歪了,后面每一个案例都要返工。

2.1 四级台阶:从单条命令到整链路排查

第一级是单点操作,一条命令解决一件事,比如按大小找文件、看某个端口在不在听。这一级的目的是建立“命令—输出”的直觉,读者要知道自己敲下去会看到什么形状的结果。第二级是组合流水线,两三条命令用管道串起来,find | xargs、awk | sort | uniq -c这类,考的是数据流的意识:上一条的输出格式决定了下一条能不能接。第三级是服务与自动化,涉及账号、权限、后台进程、定时任务、开机自启,开始出现“配置文件的写法”和“生效方式”这两个新变量。第四级是故障排查,给一个现象,比如页面 502、磁盘满、任务没跑,让读者自己按顺序排除。四级台阶的划分直接决定了案例编号的排布:1 到 40 集中在前两级,41 到 80 在第三级,最后 20 个全部是第四级。读者卡在某一步,能立刻知道自己缺的是哪一层,而不是笼统地“Linux 不熟”。

2.2 模块划分与案例配额

八个模块的划分标准是“一次排查通常只在一个模块内解决”,避免案例之间互相依赖太深——第 60 个案例如果必须先做完第 12 个才能跑,读者的挫败感会直接劝退。配额按下表分配,每个模块内的案例再按“常用度”排序,越靠前的越该会。

模块案例数代表案例验收方式
文件与目录14按大小/时间组合定位文件输出条数与预期一致
权限与账号12共享目录的组权限与粘滞位换个账号执行结果不同
文本处理16一份日志出三张统计报表统计结果可人工抽查
进程与服务14由端口反查进程与启动命令杀掉进程后现象复现
磁盘与存储12空间够却写不进去df与df -i结论不同
网络与连通12从网卡到 HTTP 的四步定位断开某一环现象变化
定时任务与自动化10timer 替代 crontab到点自动产出文件
日志与故障排查10综合场景串前七个模块按步骤单能复现结论

配额不是死的。文本处理给了 16 个,是因为它最容易被低估:很多人能背出awk的语法,却写不出“统计每个接口的 5xx 比例”这种真实需求。反过来,网络模块只给 12 个,是因为再往下走就进入抓包和协议细节,超出了这份案例集的边界,硬塞进来只会让读者在半懂不懂的状态里耗时间。

2.3 每个案例的四段式模板:场景、命令、验证、反例

一百个案例如果写法各不相同,读起来就是一本拼凑的笔记。统一模板是这份材料的骨架,每个案例固定四段:场景一句话说清“什么时候会用到”,命令给出可直接粘贴的完整片段并带注释,验证说明“看到什么算成功”,反例说明“常见写错会得到什么错误结果”。第四段是最容易被省掉的,也是最值钱的——只告诉读者正确写法,他下次还是会踩同一个坑;把错误输出摆出来,他才知道自己现在这个报错属于哪一类。

举个模板落地的样子,以“统计访问日志里状态码分布”为例,场景是“线上报错变多,先看整体盘子”;验证是“200 与 500 的条数加起来等于总行数”;反例是“awk '{print $5}'写成了$4,输出全是 URL,一眼能看出取错列”。四段凑齐,一个案例才算写完。我在整理这套结构时踩过的坑是:一开始只写命令不写反例,结果自己过两周再看,也想不起来当时为什么加那个-xdev参数。

3. 实验环境搭建:两台虚机、一个沙箱脚本撑起全部案例

案例集最尴尬的情况是“命令给了,但读者机器上跑不出同样的结果”——因为文件不存在、日志不存在、账号不存在。所以环境部分不能省,也不能写成“请自行准备测试数据”。做法是给一个沙箱脚本,一条命令把一百个案例要用的目录、账号、样本文件和日志全部生成出来,任何人拿到这份材料,五分钟内能站在同一条起跑线上。这也是答辩时最有说服力的一环:环境可重建,结论才可复现。

3.1 主机规划与目录约定

两台机器足够:一台当操作机,所有案例都在上面敲;一台当对端,专门给网络和服务类案例充当“另一头”。操作机 2 核 4G 就够,对端 1 核 2G 即可,两台放同一个内网网段,用私有地址互访。目录约定比机器配置更重要,全部案例的数据统一放在/data/lab下,子目录按用途分:files放样本文件,logs放日志,scripts放脚本,backup放备份产物,bigfile放占位大文件。所有案例只准在这个根目录里写,理由是清理时一条rm -rf /data/lab就能恢复干净,不用逐个回忆自己动过哪些路径。

角色配置装什么用途
操作机2C4G,系统盘 40G基础工具集、文本处理工具承载 90% 的案例
对端1C2G,系统盘 20G一个静态站点服务、一个监听端口网络与服务类案例的另一端
数据根目录/data/lab沙箱脚本生成全部案例的数据读写区

账号也要提前约定:建两个普通账号labuser1和labuser2,权限类案例全部靠这两个账号的差异来演示。用一个账号做完所有权限案例,等于什么都没验证——root 下一切都是通的,看不出区别。

3.2 沙箱脚本:一次生成 500 个文件和 20 万行日志

样本数据必须“有结构但不规整”,太规整了统计类案例一眼出答案,太乱了又没法人工核对。下面这个脚本把两件事一次做完:造 500 个大小随机的文件,供定位类案例使用;造 20 万行访问日志,供统计类案例使用。日志格式刻意设计成空格分隔的六列,就是为了让awk的列号好记。

#!/usr/bin/env bash # sandbox.sh —— 一键铺出 100 例所需的目录、账号与样本数据 # 用法: sudo bash sandbox.sh (只在专用实验机上执行) set -euo pipefail LAB=/data/lab # 1) 两个对照账号,权限类案例全靠它俩的差异 id labuser1 >/dev/null 2>&1 || useradd -m labuser1 id labuser2 >/dev/null 2>&1 || useradd -m labuser2 # 2) 固定目录结构,所有案例只准在这里写 mkdir -p "$LAB"/{files,logs,scripts,backup,bigfile} chown -R labuser1:labuser1 "$LAB" # 3) 500 个 1KB~200KB 的随机大小文件,供 find / du / sort 使用 for i in $(seq 1 500); do dd if=/dev/zero of="$LAB/files/f_$i.dat" \ bs=1K count=$((RANDOM % 200 + 1)) status=none done # 4) 20 万行访问日志,六列: ip 时间 方法 URL 状态码 字节数 awk 'BEGIN{ srand(7); for(i=1;i<=200000;i++){ ip = "10.0." int(rand()*4) "." int(rand()*255); st = (rand()<0.03) ? 500 : 200; # 约 3% 的 5xx url = "/api/v" int(rand()*3) "/item/" int(rand()*1000); printf "%s 2024-10-%02dT%02d:%02d:%02d GET %s %d %d\n", ip, int(rand()*28)+1, int(rand()*24), int(rand()*60), int(rand()*60), url, st, int(rand()*9000)+100; } }' > "$LAB/logs/access.log" # 5) 1G 占位文件,用来演示「磁盘满」与「删除后空间不释放」 fallocate -l 1G "$LAB/bigfile/placeholder.img" echo "sandbox ready: $LAB"

逐段说明参数含义:set -euo pipefail让脚本任何一步出错就停,避免生成半套数据还以为成功了。dd的bs=1K count=$((RANDOM % 200 + 1))决定文件大小在 1KB 到 200KB 之间随机,这个区间刚好让find -size +100k这类条件能筛出有意义的一批文件。srand(7)固定随机种子,保证谁跑都得到同一份日志——这一条很关键,否则案例里写的“预期 500 条错误”在别人机器上对不上,整份材料的可信度就没了。printf里的%02d是为了让时间字段宽度一致,按字符串排序时不会乱。最后fallocate直接占位而不是真的写入数据,速度快,也不吃 IO。

脚本跑完之后,建议先执行一遍自检:wc -l $LAB/logs/access.log应该是 200000,ls $LAB/files | wc -l应该是 500。两个数字对不上,说明中途出错了,先别往下做案例。

3.3 快照、回滚与清理边界

实验环境一定会被玩坏,这是设计里要预留的。做法是在沙箱脚本跑完、确认数据正确之后,立刻打一个快照,命名上带日期,后面每做完一个模块的案例再打一个。回滚的粒度按模块走,而不是按单个案例走——单个案例出问题,多半是命令敲错了,重敲一遍比回滚快;整个模块的结果都和文档不符,才值得回滚重来。

清理边界要写清楚:允许在/data/lab下任意删改,允许杀掉自己启动的测试进程,允许停掉自己配的测试服务。不允许动系统自带的账号、系统盘上的配置文件、防火墙的默认策略。这条边界在案例文本里要重复出现,尤其是讲rm和kill的那几个案例,前后各放一次提醒。

提示:快照不是后悔药的全部。真正省时间的是“每次动手前先确认自己在哪个目录、用的是哪个账号”,pwd和whoami这两条命令,值得在案例里单独占一个位置。

4. 高频场景的命令级拆解:六个模块的可复现写法

案例集的厚度体现在这里:不能只给命令,得给“为什么这么写”和“换个条件怎么改”。下面挑六个模块各一个代表性案例展开,写法就是整份材料的写法——先场景,再完整命令,再逐参数解释,最后说清结果不对时往哪看。

4.1 文件与权限:定位类案例的三种写法

场景很常见:磁盘告警了,得先知道是哪些文件在占地方。三条路径各有适用面,按“知道多少线索”来选。

# 案例 12:7 天内改过、且大于 10MB 的文件,按大小倒序取前 20 find /data/lab -type f -mtime -7 -size +10M -printf '%s\t%p\n' 2>/dev/null \ | sort -rn | head -20 \ | awk '{printf "%.1fMB\t%s\n", $1/1048576, $2}'

-type f排除目录,不加这一条会把目录也算进去,-printf '%s'对目录输出的值没有参考意义。-mtime -7表示修改时间在 7 个 24 小时以内,注意它是按“整天”向下取整的,边界上会有半天误差,讲时间条件的案例必须提这一句,否则读者永远对不上数。-size +10M里的M是按 1048576 字节进位计算并向上取整的,所以一个 10.4MB 的文件会被算作 11M,刚好卡在边界上。2>/dev/null屏蔽掉权限不足的报错,实验环境里经常有别的账号建的目录。最后的awk把字节换成人看的单位,%.1f保留一位小数——这一步不是炫技,是让输出能直接贴进工单。

权限方面最容易讲错的是“共享目录”这个案例。正确做法是把目录的组设成共享组、权限设成2770,其中头一位2是 setgid,作用是让目录里新建的文件自动继承目录的组,而不是继承创建者的主组。少了这个2,两个人往同一个目录里写文件,另一个人就改不了对方建的文件,现象是“明明同组却 Permission denied”,很多人会误判成权限位算错了。

4.2 进程与端口:从“谁占了 8080”倒推

# 案例 27:端口被占用,反查进程与启动命令 ss -lntp | awk 'NR==1 || $4 ~ /:8080$/' # 输出里拿到 pid 后,看它是谁、从哪启动的、工作目录在哪 ls -l /proc/<pid>/cwd tr '\0' ' ' < /proc/<pid>/cmdline; echo

ss的四个参数各有分工:-l只看监听态,-n不做端口到服务名的解析(避免输出里出现http-alt这种名字反而不好 grep),-t限定 TCP,-p显示进程信息——注意-p只有 root 或进程属主才看得到完整信息,普通账号执行会看到空列,这是最常见的“命令没问题但输出少一半”的原因。awk里NR==1保留表头,$4是本地地址列,用~ /:8080$/精确匹配端口结尾,避免把18080也匹配进来。

反过来,只知道进程名要查它开了哪些端口,把管道换成grep -w 进程名即可。再往下还有一层:进程明明在,端口也在听,但连不上,那就不是进程的问题,去看 4.6 的连通性案例。

4.3 磁盘与 inode:空间满的两种完全不同的成因

# 案例 41:空间还有,但写文件报 No space left on device df -h /data # 看块使用率 df -i /data # 看 inode 使用率,这一条最容易被忘 # 定位哪个子目录堆了大量小文件 find /data/lab -xdev -type f \ | awk -F/ '{print "/"$2"/"$3"/"$4"/"$5}' \ | sort | uniq -c | sort -rn | head

两个df的结论可能完全相反:块还剩 40%,inode 已经 100%。成因是小文件太多——每个文件至少占一个 inode,几百万个几字节的临时文件就能把 inode 吃干净,而块使用率看着很健康。这个案例的价值不在于命令,而在于建立“空间有两种”的认知,读者以后看到No space left会条件反射地敲第二遍df -i。

还有一种更隐蔽的:df显示满,但du加起来对不上。多半是文件已经被删了,可还有进程握着它的句柄没释放。

# 找出「已删除但仍被占用」的文件,按大小排序 lsof +L1 2>/dev/null | sort -k7 -rn | head

+L1的意思是“链接数小于 1”,也就是已经没有目录项指向它了。处理方式是重启持有它的进程,或者在不重启的前提下清空其内容,具体选哪种看服务能不能停。-xdev那个参数也别漏,它让find不跨文件系统,否则扫到别的挂载点会慢得离谱。

4.4 日志分析:一条 awk 出三张报表

LOG=/data/lab/logs/access.log # 报表一:状态码分布 awk '{print $5}' "$LOG" | sort | uniq -c | sort -rn # 报表二:Top 10 来源 IP awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10 # 报表三:5xx 且命中 v2 接口的行,落盘备查 awk '$5>=500 && $4 ~ /\/api\/v2\//' "$LOG" > /data/lab/logs/err_v2.log wc -l /data/lab/logs/err_v2.log

列号对应沙箱日志的六列:$1是 IP,$4是 URL,$5是状态码。这是设计日志格式时就定好的,为的是让读者不用每次都数引号和方括号——真实日志里因为字段带空格和引号,$9才是状态码,那种情况更稳妥的写法是awk -F'"' '{split($3,a," "); print a[1]}',先按引号切,再按空格切。案例集里两种写法都给,但先用简单格式讲清思路,再用真实格式补一句“线上日志要这么改”,避免一上来就被字段切分劝退。

sort | uniq -c | sort -rn这个三段式值得单独讲:第一个sort是为了让相同值相邻,uniq -c才有意义;第二个sort -rn才是按次数倒序。少了第一个sort,uniq只会合并相邻的重复行,输出看着像随机数——这是文本处理类案例里最高频的错误,反例那段直接把这种错误输出贴出来。

4.5 定时任务:crontab 与 systemd timer 的取舍

老系统上crontab够用,新系统上更推荐 timer,因为它的日志直接进journalctl,出问题能查。案例里给的是 timer 的最小可用写法。

# 案例 73:每 5 分钟跑一次报表脚本 sudo tee /etc/systemd/system/lab-report.service >/dev/null <<'EOF' [Unit] Description=lab daily report [Service] Type=oneshot User=labuser1 ExecStart=/data/lab/scripts/report.sh EOF sudo tee /etc/systemd/system/lab-report.timer >/dev/null <<'EOF' [Unit] Description=run lab report every 5 minutes [Timer] OnCalendar=*:0/5 Persistent=true [Install] WantedBy=timers.target EOF sudo systemctl daemon-reload sudo systemctl enable --now lab-report.timer systemctl list-timers --all | grep lab-report journalctl -u lab-report.service -n 20 --no-pager

三个参数决定成败:Type=oneshot表示这个服务跑完就退出,不是常驻进程,写成默认的simple会让 systemd 一直以为它还在启动中。OnCalendar=*:0/5是“每小时的第 0、5、10…分钟”,比*/5 * * * *可读性好,但注意它是按系统时区算的,机器时区不对就到点不跑。Persistent=true解决的是关机期间错过的任务,开机后补跑一次,不然“昨天晚上停机,今天早上报表是空的”这种事会反复发生。daemon-reload是改完 unit 文件后的必做动作,忘了它就等于没改,现象是“文件明明改了,行为还是老的”。

4.6 网络连通性:从网卡到 HTTP 的四步定位

# 案例 88:服务连不上,自下而上四步 ip -br addr # 1. 本机有没有拿到地址 ip route get 10.0.2.10 # 2. 走哪张网卡、下一跳是谁 ss -lntp | grep ':80' # 3. 对端端口有没有在听 curl -sS -o /dev/null \ -w '%{http_code} %{time_total}s\n' \ http://10.0.2.10/health # 4. 应用层到底返回了什么

顺序不能乱。先看地址,没地址就没有后面的故事;再看路由,地址有但路由缺失的典型现象是“内网通、跨网段不通”;再看端口,这一步要在对端执行,确认监听的是0.0.0.0:80还是127.0.0.1:80——只监听回环地址的话,本机curl一切正常,别的机器怎么都连不上,这个坑在案例里被单独列成一条反例;最后才是 HTTP 层,用curl的-w把状态码和耗时打出来,比-v的输出干净得多,-o /dev/null丢掉响应体,只留指标。

5. 避坑与排查:案例跑不出预期结果时先看这五处

一百个案例里,真正让人卡住的往往不是命令难,而是环境和权限这类“不相关”的地方。下面五条是出现频率最高的,按“现象 → 原因 → 解决”的顺序写,建议在动手之前先扫一遍。

5.1 root 下全通、普通账号报 Permission denied

现象:同一个案例,用 root 执行顺利出结果,换成labuser1就一堆Permission denied,输出条数少一截。原因不是命令写错了,而是目录权限和umask不同:root 无视大部分权限位,普通账号受umask影响,新建文件的默认权限就不一样。解决方式是所有案例固定用普通账号执行,只有必须提权的步骤(改 systemd unit、动/etc下的文件)才用sudo,并在案例文本里标出来。顺手养成习惯:动手前whoami一下,能省掉一半的困惑。

5.2 清理实验数据时路径写错

现象:想清空/data/lab/files,手一快敲成删除整个/data,或者更糟,在变量为空的情况下执行了带通配符的删除。原因是没有做路径保护和变量校验。解决方式是三条硬规矩:清空目录用rm -rf /data/lab/files/*而不是删目录本身;脚本里凡是用变量拼路径,先加set -u,再在删除前echo一遍实际路径;把alias rm='rm -i'加进实验账号的配置文件,多一次确认不会死人,少一次确认可能重装系统。

5.3 时间类案例的结果总差半天

现象:find -mtime -7数出来的文件数和文档里的预期对不上,或者按天切分的日志统计少了一天。原因通常有两个:一是系统时区和文档假设的不一致,二是用cp -p、rsync -a复制样本文件时保留了原时间戳,导致“刚刚生成的文件”修改时间是一年前。解决办法是先统一时区,再在生成样本数据之后重新touch一遍,让时间基准干净;讲-mtime的案例里明确写出“按整天向下取整”这句,边界差半天是正常现象,不是命令错了。

5.4 定时任务手动执行成功、到点不执行

现象:脚本手动bash report.sh跑得好好的,配成定时任务之后什么都不产出,日志里也没有报错。原因基本是环境不同:定时任务的PATH比登录 shell 短得多,脚本里调用的命令找不到;或者没有设置工作目录,脚本里的相对路径全部失效。解决办法是脚本开头显式声明PATH、用绝对路径调用所有外部命令、cd到确定的工作目录再执行;排查时看journalctl -u 服务名或系统邮件,不要凭猜。

5.5 本机 curl 通、别的机器连不上

现象:在服务所在机器上curl 127.0.0.1:8080一切正常,从对端机器访问超时。原因是服务只监听了回环地址,或者中间隔着一层防火墙规则。解决办法是先在对端执行ss -lntp | grep 8080看监听地址,127.0.0.1:8080和0.0.0.0:8080是两件完全不同的事;再看防火墙规则有没有放行该端口。这两步走完还没通,才轮到抓包这种重手段,别一上来就上最重的工具。

6. 验收与答辩:怎么证明这一百个案例是自己真跑过的

案例集这类材料,最大的质疑是“是不是抄的”。要打消这个质疑,靠的不是解释,是证据链:环境能重建、案例能复现、结果能核对、异常能解释。我一般会把验收拆成两层,一层是自动跑的,一层是当场演示的。

自动层用一个极简的校验脚本就够,每个案例目录下放run.sh和expect.txt,跑完对比输出。这样一百个案例的完成度是一个数字,不是一句“我做完了”。

#!/usr/bin/env bash # verify.sh —— 顺序跑全部案例,用 diff 判定通过与否 pass=0; fail=0 for d in /data/lab/cases/*/; do name=$(basename "$d") bash "$d/run.sh" > "$d/actual.txt" 2>&1 if diff -q "$d/expect.txt" "$d/actual.txt" >/dev/null; then pass=$((pass+1)); printf 'PASS %s\n' "$name" else fail=$((fail+1)); printf 'FAIL %s\n' "$name" fi done printf 'total=%d pass=%d fail=%d\n' $((pass+fail)) "$pass" "$fail"

expect.txt里只放稳定的部分:条数、排序后的前几行、关键字段的值。别把耗时、时间戳这类每次都变的内容写进去,否则脚本永远在报 FAIL,最后没人看它。diff -q只判有无差异,比对的细节留给diff手动跑。

当场演示层按下面这张表准备,每项都能在三分钟内给出证据:

验收项怎么证明常见追问
环境可重建删掉/data/lab,重跑一次沙箱脚本数据是随机的吗
案例可复现随机抽三个案例现场敲为什么用这个参数
结果可核对展示expect.txt与actual.txt的比对失败的那几个怎么回事
异常可解释现场改错一个参数,说出报错含义你怎么定位的
文档可交接展示案例四段式模板别人能照着做吗

答辩的时候最容易翻车的不是不会,而是“跑得太快”。三分钟演示里,抽三个案例就够:一个定位类,展示find的条件组合;一个统计类,展示awk取列与三段式排序;一个排查类,现场把服务监听地址改成回环,让对面连不上,再改回来。观众看到现象变化,比看十页截图都管用。被问到“为什么用这个参数”时,答“文档里这么写的”是最差的回答,要答出这个参数省掉了什么麻烦,比如-xdev省掉了跨文件系统扫描的时间,Persistent=true省掉了停机期间漏跑的任务。

从那以后我每次整理这类案例材料,都强制走一遍“删环境、重跑脚本、跑校验、抽三个现场演示”的流程,哪怕前面已经验过两次。因为我吃过一次亏:演示前一天手滑改了一个样本文件,第二天现场diff一跑,满屏 FAIL,临时解释什么都像借口。希望这套结构和验收方法,能帮到你把自己那份方案稳稳交出去。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询