☰
Linux系统管理实操:从命令细节到运维面试的完整练习指南
2026/10/3 9:57:32 网站建设 项目流程

我见过不少学 Linux 的朋友,笔记记了三大本,常用命令大全收藏了不下五个版本,可真到了生产服务器上处理一个问题,第一反应还是打开搜索引擎现查。Linux 这东西,本质上是练出来的手艺,不是看出来的知识,尤其是 Linux 系统管理这个方向,命令敲错一次记得比背十遍都牢。这篇 LINUX 练习记录是我自己的第二轮实操复盘,内容集中在常用命令的隐藏细节、进程管理与进程改名、用户权限与 sudo 配置、存储和 NAS 挂载、Shell 脚本重构,以及运维面试高频题的现场推演。如果你已经会 cd、ls、vim 这些基础操作,想往系统管理、运维方向扎实走一步,或者正在准备运维岗位的面试,这篇练习清单应该能直接拿来当训练脚本用。

1. 练习前的环境准备:快照、日志与镜像源

动手之前先把场地搭好。不是所有练习都能放心大胆地在云服务器上做,有些命令按下去,后果是没法撤销的。我自己的做法是:本地跑一台虚拟机,专门用来做各种"破坏性"练习,唯一的底线是快照一定要勤打。这样玩脱了随时回滚,比对着教程背一百遍都管用。

1.1 发行版和镜像源的取舍

练习用的发行版怎么选,得看你最终想去什么环境干活。如果目标是企业运维岗位,RHEL 系是主流,我推荐 Rocky Linux 9 或者 AlmaLinux,命令体系和文档生态跟商业发行版基本一致;如果平时搞开发、玩容器,Debian 系更顺手,apt 装软件比 rpm 系快不少。

很多新手纠结"哪个发行版最好",其实没必要。真正的关键是:你至少要在两个家族的环境里都练过一遍,因为apt和yum/dnf的包管理逻辑、配置文件位置、服务管理方式都有差异。我在练习机里装了两台虚拟机,一台 Rocky Linux,一台 Debian,遇到需要验证"换个发行版会不会不一样"的场景,直接切过去试。这比在网上问"CentOS 还能不能用"有效率得多。

装完系统后,第一件事往往是把软件源换成访问速度快的国内镜像。以 Debian 13(trixie)为例,改动主要在/etc/apt/sources.list.d/下的.sources文件,把默认的deb.debian.org换成镜像站点地址,然后跑一遍sudo apt update。这个操作本身不难,但值得专门练一次,因为你会顺带理解源地址的书写格式、组件名(main、contrib、non-free)的含义,以后添加第三方源也不会慌。

1.2 快照、练习日志和历史命令时间戳

虚拟机的快照功能是我练习时的保命符。无论是改错了 fstab、搞坏了引导,还是把系统服务删得七零八落,只要快照在手,几分钟就能回到干净状态。我的习惯是:每做完一组练习、确认又是全新的踩坑经验时,打一个新快照,命名里写上日期和练习主题,例如2025-01-sudoers、2025-01-nfs。这样回滚时能清楚地知道每个快照对应什么状态,而不是面对一排Snapshot 1 2 3猜谜。

练习日志是另一件容易被忽略但收益极大的事。我给自己配了两个小工具:一是给history加上时间戳,不然两天后回头看历史记录,完全想不起哪条命令是哪天敲的。在~/.bashrc里加一行:

export HISTTIMEFORMAT="%F %T "

然后source ~/.bashrc。此后用history查看时,每条命令前面都会带上日期时间,复盘时能还原当时的操作顺序。

二是用script命令录屏。script会把整个终端会话的输入输出原样写进文件,比起事后回忆,这个日志可是原原本本的黑匣子:

script -a ~/practice_$(date +%F).log

练习结束输入exit,文件里就保留了你敲的每一条命令和输出结果。写博文复盘、向同事描述问题、甚至面试时讲案例,这个日志就是最硬核的素材。

1.3 虚拟机蓝屏与内核崩溃的兜底思路

练习中遇到"虚拟机安装 Linux 蓝屏"这类问题,先别急着重装。蓝屏大概率不是系统坏了,而是虚拟化设置没开对:进 BIOS 确认 Intel VT-x/AMD-V 已开启,VirtualBox 里给虚拟机分配的内存不要低于 2GB,显存调大一点,启动方式在 EFI 和传统 BIOS 之间切换试试,这几项能解决九成以上的安装失败。

比蓝屏更值得练的是内核崩溃后的恢复。我专门做过一组练习:故意改坏/etc/fstab、删掉关键系统库的软链接,然后强制重启,观察系统如何进入紧急模式,练习用单用户模式或init=/bin/bash引导参数绕过问题,把配置改回来。这套流程在实际工作中价值极高——服务器挂了不是稀奇事,稀奇的是你能不能在最短时间内把它拉起来。练习时把恢复步骤写成清单,每次出问题按清单走一遍,熟能生巧。

2. 常用命令实战:find、rm、grep 的隐藏陷阱与管道细节

网上流传的"Linux 常用命令大全"满天飞,但命令会敲和敲对是两回事。这一组练习是我特别设计的"陷阱专项",专门找那些看着简单、一用就错的细节。

2.1 find、rm、grep 的几个"想当然"错误

先说find。很多人只会find / -name "*.log",但实际排查问题时,-mtime、-size、-type组合起来才是主角。比如清掉 7 天前的归档日志,标准写法是:

find /var/log/app -name "*.log" -type f -mtime +7 -delete

这里有个容易翻车的点:find的多个条件默认是"与"关系,但如果你写成find . -name "*.log" -o -name "*.tmp" -delete,逻辑就变成了"名字匹配 *.log,或者(名字匹配 *.tmp 且执行删除)",结果可能把所有 *.tmp 文件删掉,而 *.log 一个没动。正确做法是加括号分组:

find . \( -name "*.log" -o -name "*.tmp" \) -delete

再说rm。rm -rf是每个 Linux 用户的噩梦,但比它更容易出事故的是变量展开。比如脚本里写rm -rf $dir/,如果$dir因为某种原因没取到值,命令就变成了rm -rf /。我自己的规矩是:脚本里所有路径变量一律加引号,并且用--明确结束选项解析:

rm -rf -- "$dir"

另外,rm -rf /var/log/app/和rm -rf /var/log/app看起来差不多,但前者的路径解析可能涉及目录本身,某些老版本会有差异。练习时我专门对比过,结论是:不要在命令行和脚本里混用带不带结尾斜杠的写法,统一不带斜杠并加引号。

grep的常用参数也要练到条件反射的程度。grep -E用扩展正则,grep -v取反,grep -l只列文件名,grep -r递归搜索目录。这里有个坑:grep -v配合管道时,如果上游命令出错导致没有输出,grep -v "xxx"会返回成功状态,掩盖真实错误。后面讲管道时会专门说这个问题。

2.2 管道、重定向和进程替换的排障基本功

管道和重定向是 Linux 的"组装线",但也最容易写出隐藏 bug。第一个要练透的是文件描述符的顺序。2>&1放在哪里,结果完全不同:

# 正确:标准输出和标准错误都写入 log 文件 command > log 2>&1 # 错误:标准错误被重定向到了"重定向之前"的标准输出位置 command 2>&1 > log

第二行里,2>&1在> log之前执行,此时标准输出还指向终端,所以标准错误会跑到终端上,而标准输出才进文件。这个顺序问题在排障时特别容易迷惑人:日志文件里干干净净,报错却出现在屏幕上。

第二个要练的是set -o pipefail。默认情况下,管道命令的返回状态取决于最后一个命令,也就是说cmd1 | cmd2里即使cmd1崩了,只要cmd2成功,整个管道的返回码就是 0。这在脚本里很危险。在脚本开头加上set -o pipefail,就能让管道返回第一个非零状态,再加上set -e,出错时脚本才会真的停下来。

进程替换也是在排障中很实用的技巧,但很多人没用过。比如对比两个目录里的文件名差异:

diff <(ls dir1) <(ls dir2)

这里的<( )会把命令输出包装成一个伪文件,传给diff。比起先输出到临时文件再清理,这种方式干净得多。我在练习时会刻意多用这类结构,熟悉之后写临时方案会顺手很多。

2.3 command not found 的完整排查链路

"命令找不到"是新手提问区出现频率最高的问题,但排查思路其实很固定。先分清是哪种"找不到":

  • 命令本身存在,但不在 PATH 里:用type -a 命令名或command -v 命令名确认。
  • 路径输入但权限不够:./script.sh报 Permission denied,那是没加执行权限。
  • 命令不存在:which、whereis、type都无输出,那就是没装。

排查时我喜欢按这个顺序来:先echo $PATH看看有没有包含该命令的实际安装目录,比如/usr/local/bin、/usr/bin;再用command -v确认 shell 能否找到;最后用ls -l确认文件是否有执行权限。如果二进制文件存在但一运行就报error while loading shared libraries,那多半是动态库缺失,用ldd /usr/bin/具体命令查看哪些库显示not found,再从系统盘里把对应库文件恢复回来。

还有一个很容易被忽略的地方:脚本第一行的 shebang。如果#!/bin/bash写成了#!/bin/bashx,直接./script.sh会报"无法执行",因为系统按 shebang 找解释器时根本找不到这个路径。这类问题看报错信息就能定位,但很多人习惯性把锅甩给"脚本坏了",多练几遍就有感觉了。

3. 进程管理练习:信号、进程改名与 CPU 排查

进程管理是 Linux 系统管理的核心,也是面试必考的方向。这一组练习我从"怎么看进程"一直做到"怎么改进程名字",顺带把一次 CPU 飙高的排查流程完整走了一遍。

3.1 进程视图与信号:别一上来就 kill -9

先练"看"。ps aux和ps -ef是两种最常见格式,前者侧重 CPU/内存占用,后者侧重父子关系。真正排查问题时,我更喜欢用自定义输出字段:

ps -eo pid,ppid,%cpu,%mem,etime,user,cmd --sort=-%cpu | head -20

这条命令按 CPU 使用率排序,能一眼看到最耗资源的进程。etime显示进程存活时间,对判断"是不是刚起来就吃满 CPU"很有帮助。

信号这一块,新手最大的误区是"杀进程只会 kill -9"。kill -9是强制杀死,进程没有机会清理临时文件、释放锁、写最后的日志,极端情况下会造成数据损坏。正确的信号选择应该是:

信号数字用途典型场景
SIGHUP1挂断/重读配置让 nginx、sshd 重新加载配置
SIGINT2中断Ctrl+C 触发,正常退出
SIGTERM15终止kill 默认信号,请求进程优雅退出
SIGKILL9强制杀死进程无响应时才用
SIGSTOP19暂停暂停进程执行
SIGCONT18继续恢复暂停的进程

练习时我专门做了一个实验:起一个sleep 1000,先发SIGTERM,观察进程如何退出;再起一个不响应 SIGTERM 的进程(比如卡在不可中断 IO 状态的进程),最后才用kill -9。这样能直观感受到两者的差别。实际工作中,重载服务配置用的是kill -HUP,比如:

kill -HUP $(cat /run/nginx.pid)

不对配置文件做语法检查的服务,用 HUP 信号比直接重启更安全,因为不会中断连接。

3.2 给进程改名的几种实现:prctl、exec -a 和 setproctitle

"Linux 修改进程名称"这个需求在监控场景里非常常见。默认情况下,你用 Python 跑十个 worker,进程列表里全是python app.py,根本分不清谁是谁。于是就有了改进程名的需求。我练习时整理了三种主流做法。

第一种,从底层改 task comm。在 C 语言里用prctl(PR_SET_NAME, ...)设置进程名,它改的是内核里的 task name,也就是/proc/PID/comm的内容,但注意这个字段最长 15 个字符。

第二种,shell 层面的exec -a。bash的exec命令支持指定新的argv[0]:

bash -c 'exec -a my_task sleep 1000' & ps -ef | grep my_task

用ps -ef看,进程显示的名称就是my_task。这种做法改的是cmdline的第一个参数,适合快速起一个"有名字"的后台进程,但不会改/proc/PID/comm。

第三种,Python 用第三方库setproctitle,效果最接近生产需求,能把命令行和 comm 都改掉:

pip install setproctitle
import setproctitle setproctitle.setproctitle("worker_pool_01")

这样在top和ps里都能看到自定义名称,监控报警时一眼就能定位是哪个模块出了问题。如果你用 systemd 管理服务,其实更推荐的做法是在 unit 文件里明确指定服务描述和进程名规则,通过systemctl管理,而不是让进程自己改名。

3.3 一次 CPU 飙高的联动排查练习

进程管理练到最后,一定要做一次综合实战。我构造了一个场景:某个 Java 服务 CPU 使用率 99%,要求在不重启服务的情况下定位问题。排查顺序我总结为"从外到内、从粗到细、先看后碰"。

第一步,top看到占用 CPU 的进程 PID;第二步,top -Hp PID查看进程内部哪个线程在消耗 CPU,这里记下线程号;第三步,用strace跟踪这个线程的系统调用:

sudo strace -f -p 线程号 -e trace=network,file,write -o /tmp/trace.log

这一步能看出进程到底在做什么操作——是频繁读写磁盘、反复网络连接失败,还是陷入某个死循环。与此同时,打开/proc/PID/目录看进程的 open files、环境变量和 status:

ls -l /proc/PID/fd | head -20 cat /proc/PID/status | grep -E "State|Threads|voluntary"

整个排查的关键不是背命令,而是理解每一步在验证什么:top定位对象,strace观察行为,/proc获取现场信息。这套联动方法练顺了,以后遇到性能问题,思路会很清晰。

4. 用户权限强化:密码策略、权限位、sudo 最小化

用户和权限是 Linux 安全的地基。这一轮练习我把重点放在了三件事:密码策略过期提醒、权限位与 umask 的实战计算、sudo 配置的最小化原则。

4.1 建用户、配密码策略、设置过期提醒

useradd和adduser的区别值得先搞清楚。adduser在 Debian 系是交互式脚本,会顺手建家目录和密码;useradd是裸命令,参数更细。生产环境里更常用useradd加参数:

sudo useradd -m -s /bin/bash ops sudo passwd ops

-m创建家目录,-s指定登录 shell。接着用chage设置密码策略:

sudo chage -M 90 -W 7 -m 7 ops sudo chage -l ops

-M 90表示密码 90 天后过期,-W 7表示过期前 7 天开始提醒,-m 7表示修改密码后至少 7 天才能再改。全局默认值在/etc/login.defs里。

密码过期提醒这件事,网上问的人很多。系统默认只会在用户登录时提示"密码将过期",但如果用户长期不登录,提醒就发不出去。我练习时写了一个每日检查脚本:遍历系统用户,用chage -l解析到期时间,提前 7 天发邮件通知。逻辑不复杂,核心命令是:

sudo chage -l ops | grep "password must be changed"

解析出日期,跟当前日期做差,小于 7 天就通过mailx发信。这个脚本把"过期提醒"从依赖用户登录变成了主动通知,在生产环境里是非常实用的加固手段。

4.2 权限位、umask 和 ACL 的实战计算

权限这块,先别急着背chmod 777,要理解权限数字怎么来的。rwx对应421,读 4、写 2、执行 1,组合相加就是权限位的数字。chmod 755 file等于所有者 rwx、属组 r-x、其他人 r-x。练习时我建议自己写个小表,把常见的权限组合(600、640、644、750、755)对应的场景列出来,比如配置文件一般 600 或 640,可执行脚本 750,共享目录 775。

特殊权限位也是面试常客。SUID 让程序以文件所有者的身份运行,典型例子是passwd;SGID 让新建文件继承目录的属组,常用于团队协作目录;Sticky bit 限制只有文件所有者能删除,/tmp目录就是典型。设置方式分别是chmod 4xxx、chmod 2xxx、chmod 1xxx。

umask的坑在于它和权限是"相减"关系。umask 022意味着新建文件的默认权限是 666 去掉 022 的写权限,得到 644;新建目录是 777 去掉 022,得到 755。这个计算看似简单,但如果你把 umask 设置成 027,就会发现同组用户读不了你的新文件。练习时我特意在一个共享目录里用不同 umask 建文件,验证权限差异,比光看教程印象深多了。

ACL 是权限管理的进阶。有时候需求是"让 ops 用户对这个目录有写权限,但其他人保持只读",用传统的属组设置很别扭,ACL 就直接解决:

sudo setfacl -m u:ops:rw /data/shared getfacl /data/shared

ACL 的权限会覆盖传统属组权限,但也受 mask 限制。练习时最容易踩的坑是:设置完了发现实际有效权限和预期不符,一查getfacl发现mask: r-x挡住了写的部分,说明要先setfacl -m m::rwx调整 mask。这个细节在日常排障中非常常见。

4.3 sudoers 的常见误区和配置验证

sudo配置有且只有一个正规入口:visudo。它会在保存前检查语法,配置写错不至于让你直接失去 root 权限。练习时我从最简到常用,逐条加配置:

# 允许 ops 用户免密执行 systemctl 和 journalctl ops ALL=(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/journalctl # 允许 deploy 组执行所有命令但需要密码 %deploy ALL=(ALL) ALL

这里要理解 sudoers 的匹配顺序:从上往下,最后匹配的规则生效。所以如果你写了ops ALL=(ALL) ALL,后面的NOPASSWD限制不会对它生效,需要调整规则顺序。

配置完之后一定要验证:

sudo -l -U ops

这条命令列出 ops 用户实际能执行的 sudo 规则,比肉眼看配置文件靠谱。我的练习里专门做了一个"故意写错"实验:把规则语法写错,保存时visudo直接报错,然后练习用pkexec或直接以 root 身份进入系统修复/etc/sudoers。整个流程走一遍,你会对 sudo 的机制和"最小权限"原则理解得更深。顺便提醒一句:sudo 权限配置过宽是系统被攻破之后最常见的提权入口来源,日常管理中尽量只授权具体命令,别图省事给ALL。

5. 存储挂载练习:UUID、NFS/CIFS 和 NAS 完整流程

存储一直是 Linux 练习里的重头戏,尤其是挂载 NAS 这种需求,每次都能在技术社区里看到一堆提问。其实挂载的本质并不复杂,复杂的是各种边界情况。

5.1 挂载原理与 UUID:为什么别用 /dev/sdX

Linux 里"一切皆文件",硬盘、分区、U 盘都对应/dev下的设备节点。挂载就是把一个设备(或网络文件系统)关联到某个目录上,之后访问这个目录就是访问设备里的数据。查看块设备和挂载关系,用lsblk和findmnt最直观:

lsblk findmnt

挂载命令本身很简单:mount 设备 挂载点,卸载umount 挂载点。但生产环境里我强烈建议在/etc/fstab里用 UUID 而不是/dev/sdX的设备名。原因在于设备名的分配顺序不稳定:你插了块 U 盘,原来的/dev/sdb可能变成/dev/sdc,按设备名挂载就会挂错甚至挂不上。UUID 是文件系统创建时生成的全盘唯一标识,跟设备顺序无关。

查看 UUID 用下面命令:

blkid

fstab 的每一行有六个字段:设备、挂载点、文件系统类型、挂载选项、是否 dump、是否 fsck 检查。一个典型的例子:

UUID=xxxxx /data xfs defaults 0 2

改完 fstab 必须先验证再重启:

sudo mount -a

这条命令会按 fstab 尝试挂载所有未挂载的条目,如果报错立刻能发现,就不用等重启后进紧急模式再哭了。

5.2 挂载 NAS(NFS/CIFS)的完整流程

NAS 挂载主要分两种协议:NFS 适合 Linux 服务器之间共享,CIFS/SMB 适合连接群晖这类成品 NAS 或 Windows 共享。练习时我把两种都配了一遍。

NFS 客户端侧的操作:

# Debian 系 sudo apt install nfs-common # RHEL 系 sudo yum install -y nfs-utils sudo mkdir -p /mnt/nas_nfs sudo mount -t nfs 192.168.1.100:/volume1/share /mnt/nas_nfs -o rw,vers=4.2

CIFS 的流程麻烦一点,需要先装cifs-utils,然后指定共享路径和账号:

sudo apt install cifs-utils sudo mkdir -p /mnt/nas_cifs sudo mount -t cifs //192.168.1.100/share /mnt/nas_cifs \ -o username=admin,password=xxxx,uid=1000,gid=1000,iocharset=utf8,vers=3.0

这里uid和gid参数很关键,它决定挂载后文件在 Linux 侧看到的属主。如果不指定,你可能会看到所有文件都属于 root,普通用户只能干瞪眼。练习时我还特意验证了vers=3.0和vers=1.0的差异——老旧的 NAS 可能只支持 SMB1,但现代系统出于安全考虑默认关闭了 SMB1。能用 3.0 就不用 1.0,这是安全底线。

要把挂载固化到 fstab,密码不建议直接写在文件里,因为 fstab 是全球可读的。更安全的方式是写到单独的凭据文件,并收紧权限:

//192.168.1.100/share /mnt/nas_cifs cifs credentials=/etc/nas.cred,uid=1000,gid=1000,iocharset=utf8 0 0

/etc/nas.cred内容两行,username=...和password=...,然后sudo chmod 600 /etc/nas.cred。整体挂载流程跑通之后,再用mount -a验证 fstab 无误,这台机器的 NAS 存储就稳定了。

5.3 device is busy 与 fstab 错误修复

练习中一定会遇到umount报target is busy的情况。原因很简单:还有进程在挂载点里读写文件。你当然可以暴力umount -l延迟卸载,但那只适合紧急情况。规范的排查是先找到是谁占用了目录:

sudo fuser -vm /mnt/nas_cifs sudo lsof +D /mnt/nas_cifs

找到占用进程后,正常退出它,再umount。我在练习时专门起了一个cd到挂载目录的sleep进程,然后尝试卸载,完整走了一遍"发现占用-定位进程-终止进程-成功卸载"的流程。别看简单,生产环境里大多数卸载失败都是这个原因。

fstab 写错导致开机进紧急模式的场景,我建议每个人都在虚拟机里练一次。出现的典型现象是:重启后进 emergency mode,只读文件系统,各种命令报错。恢复步骤如下:

  1. 输入 root 密码进入 shell。
  2. 重新以读写方式挂载根分区:mount -o remount,rw /。
  3. 用vim或nano修正/etc/fstab。
  4. 执行mount -a验证配置正确。
  5. 重启。

这套流程走顺了,你在遇到真实服务器的 fstab 故障时,就不会慌到只会重装系统。说到底,运维的基本功就是把常见故障练成肌肉记忆。

6. 脚本实战:日志归档脚本的两次重构与定时任务

Linux 练习到后期,一定要落到脚本上。脚本不是炫技,而是把重复劳动自动化。这一节我用一个日志归档脚本作为案例,展示从"能跑"到"靠谱"的重构过程。

6.1 第一版:能跑就行

需求很简单:把/var/log/app下 7 天前的.log文件打包压缩,移到/backup,然后删除原文件。新手第一版通常会写成这样:

#!/bin/bash cd /var/log/app for f in $(ls *.log); do if [ $(stat -c %Y "$f") -lt $(date -d '-7 days' +%s) ]; then tar czf /backup/$f.$(date +%F).tar.gz $f rm -f $f fi done

这版能跑通,但浑身是雷。最大问题在$(ls *.log)——如果文件名里有空格,for循环会把一个文件名拆成多个;如果目录里一个日志文件都没有,ls会报错,脚本直接卡住。其次,stat比较时间戳的方式啰嗦且容易出错,不如直接用find -mtime。最后,脚本没有任何保护机制,路径写错、目录不存在,都可能造成误删。

6.2 第二版:面向异常和文件的健壮性

重构后的版本我称之为"能上生产"的形态:

#!/bin/bash set -euo pipefail log_dir=${1:-/var/log/app} backup_dir=${2:-/backup} days=${3:-7} mkdir -p "$backup_dir" cd "$log_dir" 2>/dev/null || { echo "目录不存在: $log_dir"; exit 1; } cutoff=$(date -d "-${days} days" +%s) find . -maxdepth 1 -name "*.log" -type f -mtime "+${days}" -print0 | while IFS= read -r -d '' f; do base=$(basename "$f") tar czf "$backup_dir/${base}.$(date +%F).tar.gz" "$base" rm -f "$f" echo "已归档: $base" done

这版的改进是本质性的。set -euo pipefail让脚本在变量未定义、命令失败、管道异常时主动退出,而不是带着错误继续跑;find -mtime直接筛选超过 7 天的日志,不再做繁琐的stat比较;-print0配合read -d ''正确处理带空格的文件名;脚本参数用${1:-默认值}支持传参,可复用性大大提升。

这里有一个很隐蔽的坑值得单独讲:while循环放在管道右侧时,循环体运行在子 shell 中。如果你在循环里给外面的变量累加计数,循环结束后变量值不会变化。解决方法是改用进程替换:

while IFS= read -r -d '' f; do ... done < <(find . -maxdepth 1 -name "*.log" -type f -mtime "+${days}" -print0)

这样循环就在当前 shell 中运行,计数和状态都能保留。这个细节在面试中属于"加分项",实际写脚本时也经常遇到。

6.3 结合定时任务和系统命令,做成一个"小需求"

脚本写完不算完,要把它接入系统。我给自己设定的综合练习是:新建一个ops用户,把归档脚本部署到/opt/scripts/,用 cron 每天凌晨执行,并写日志。

步骤分解下来,每一项都是前面练习过的东西:

sudo mkdir -p /opt/scripts sudo cp backup.sh /opt/scripts/ sudo chmod 750 /opt/scripts/backup.sh sudo chown root:ops /opt/scripts/backup.sh sudo crontab -u ops -e

cron 里加一行:

5 2 * * * /opt/scripts/backup.sh /var/log/app /backup 7 >> /var/log/backup_cron.log 2>&1

这里有两个易错点:一是 cron 环境非常精简,脚本内部要尽量用绝对路径,不要依赖~或相对路径;二是>>追加日志是必需的,不然 crontab 执行结果会通过 mail 发出去,而最小化安装通常没有 mail 服务,输出就丢了。

顺带说一个现在很常见的个性化需求:很多人玩本地大语言模型,用 ollama 下载模型后发现主目录空间不够,想改存储路径。本质上这也是"环境变量 + 目录管理"的组合练习。设置OLLAMA_MODELS=/data/ollama环境变量,或者在 systemd 服务文件里写Environment="OLLAMA_MODELS=/data/ollama",再重启服务即可。如果服务已经运行,别忘了把旧的~/.ollama/models内容搬过去。这类问题看着花哨,底层还是环境变量的作用域和目录挂载那点事。

7. 面试题和故障复盘:进程通信、磁盘写满、服务排查

练习的最后一部分,我把它当成"面试模拟考场"。把热门的 Linux 面试题和真实故障案例放在一起复盘,比单纯刷题有效得多。

7.1 进程间通信与高频概念题

"Linux 进程间通信"是面试官最喜欢深挖的话题。主流方式包括:管道(pipe)、信号(signal)、消息队列、共享内存和套接字(socket)。我的理解框架是:

  • 管道适合有亲缘关系的进程之间单向传递数据,命令行里的|就是匿名管道。
  • 信号用于异步通知,比如SIGTERM、SIGINT。
  • 消息队列适合进程间传递结构化消息,查看和管理用ipcs。
  • 共享内存是速度最快的 IPC 方式,但需要配合信号量等同步机制。
  • 套接字不仅能本机通信,还能跨网络,是分布式系统的基础。

还有一个高频问题:僵尸进程怎么产生、怎么处理。子进程退出后,父进程没有调用wait收尸,子进程就变成僵尸状态,ps -ef里显示Z。僵尸进程本身不占 CPU,但会占 PID 资源。处理方式通常是杀掉父进程,让init接管并回收;如果是自己写的程序,必须在代码里正确处理子进程退出信号。

目录结构也是面试必问。我练习时整理了一份速记表,重点就几个:

目录作用实践注意
/etc配置文件改前备份,改后验证
/var动态数据、日志日志清空要截断而非删除
/proc内核和进程的虚拟文件系统排查进程现场的第一手资料
/sys内核设备信息很多调优参数在这里
/tmp临时文件重启会清理,别放重要数据
/usr系统软件系统升级主要动这里

7.2 磁盘写满和日志清空的两个经典"陷阱题"

磁盘写满是运维最常见的故障,但很多人一上来就df -h,然后误删文件,结果空间一点没释放。原因很经典:文件被某个进程占用着(比如还在写的日志),你用rm删除了路径,但进程还持有文件描述符,数据块没有被释放。

正确的排查顺序是:先用df -h确认哪个分区满了,再用du从根目录逐级往下找大目录:

df -h sudo du -x -h --max-depth=1 / 2>/dev/null | sort -h | tail -20

找到可疑目录后,用lsof查找被删除但仍被占用的文件:

sudo lsof +L1 | grep deleted

看到文件后面带着(deleted)标记,就说明它还在被某个进程占用。处理方式是重启对应进程,或 truncate 这个文件而不删除,空间才会真正释放。

"清空日志文件"这个操作,正确姿势是截断而不是删除。> file、truncate -s 0 file、: > file都是截断,日志文件依然存在,进程持有的文件描述符不变,空间立即释放。而echo "" > file会往文件里写一个换行符,严格来说不是完全清空。我们在练习中把几种写法都执行了一遍,然后用ls -l对比文件大小,结论一目了然。日常如果有日志轮转需求,优先配置logrotate,不要每天手动清。

7.3 网络与服务不可用时的排查顺序

服务连不上,第一反应别去改防火墙。我的推荐顺序是:先确认网络通不通,再看服务监听状态,然后查服务日志。

第一步,ping网关和对方主机,确认链路层没问题;第二步,ss -lntp查看目标端口是否在监听,ss比老旧的netstat信息更全;第三步,systemctl status 服务名看服务是否 active,如果挂了,journalctl -xe或/var/log/下的具体日志文件会给出原因。

以 nginx 为例,排查链路是:

ss -lntp | grep 80 systemctl status nginx sudo tail -100 /var/log/nginx/error.log sudo journalctl -u nginx --since "10 minutes ago"

如果端口在监听但外部访问不通,再考虑防火墙策略。查看防火墙规则时注意:RHEL 系是firewalld,Debian 系可能是ufw,规则语法完全不同。

整个排查过程练下来,我的体会是:Linux 运维最值钱的不是会背多少命令,而是知道在什么节点用什么工具、每个工具的输出说明什么。这一轮练习里所有踩过的坑、重构过的脚本、排查过的故障,本质上都是在训练这种"条件反射"。如果你是按这篇顺序一起练的,建议每做完一组练习就打一个快照、写几行简短记录,过两个月回头看,你会发现自己对 Linux 的手感已经完全不一样了。

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

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

立即咨询