简介
正在运行的 Linux 系统不只是文件的集合。内核负责管理硬件和进程,每条命令都会作为一个带有标识符的进程运行,而 Shell 会跟踪前台和后台作业。管理员通常会先观察系统状态,再对最相关的进程采取操作。
在本实验中,你将识别操作系统和内核,解读系统运行时间与负载平均值,检查进程之间的关系,按名称查找进程,发送终止信号,练习交互式作业控制,理解退出状态,使用 nohup 运行与终端分离的命令,并读取最新的内核消息。
识别系统并解读负载
在本步骤中,你将识别内核和发行版,检查系统已运行的时间,并了解负载平均值所表示的含义。
创建并进入工作目录:
mkdir -p /home/labex/project/process-lab
cd /home/labex/project/process-lab
uname 命令用于报告内核信息。选项 -s、-r 和 -m 分别用于选择内核名称、内核版本和机器架构:
uname -srm
uname -a 会在一行中显示所有可用字段:
uname -a
内核与 Linux 发行版并不是同一个概念。读取发行版元数据:
cat /etc/os-release
查找 NAME、VERSION 和 ID 等字段。接下来,检查系统运行时间和负载:
uptime
输出内容包括当前时间、系统已运行的时长、已登录用户数,以及三个负载平均值。这些平均值表示大约在过去 1 分钟、5 分钟和 15 分钟内处于可运行状态或不可中断状态的工作量。它们不是百分比,具体含义还取决于 CPU 核心数。
查看内核记录的简要负载信息:
cat /proc/loadavg
开头的三个值对应负载平均值。后续字段显示可运行任务数以及最近分配的进程 ID。
保存一份简要的系统摘要,供后续参考:
uname -srm > system-summary.txt
uptime >> system-summary.txt
cat system-summary.txt
该文件应包含一行内核信息和一行系统运行时间信息。
检查进程和资源活动
在本步骤中,你将检查进程标识符、父子关系和状态,并查看系统资源活动的快照。
进程就是正在运行的程序。每个进程都有一个进程 ID,即 PID。大多数进程还拥有一个父进程 ID,即 PPID,用于标识启动它们的进程。
ps 命令用于显示进程快照。选择需要的字段,并按 PID 排序:
cd /home/labex/project/process-lab
ps -eo pid,ppid,user,stat,comm --sort=pid | head -n 15
选项 -e 用于选择所有进程,-o 用于定义输出列:
PID表示进程标识符。PPID表示父进程标识符。USER表示进程所有者。STAT表示进程状态以及可选标志。COMMAND表示可执行文件名称。
常见的状态字母包括:R 表示正在运行,S 表示可中断睡眠,D 表示不可中断睡眠,T 表示已停止,Z 表示僵尸进程。处于睡眠状态的进程通常只是在等待工作。
BSD 风格的 ps aux 形式会提供 CPU 和内存列,以及完整的命令行:
ps aux | head -n 10
交互式使用 top 时,它会持续更新。批处理模式可以生成一份稳定快照:-b 选择批处理输出,-n 1 请求只更新一次。
top -b -n 1 | head -n 12
顶部信息汇总了系统运行时间、负载、任务状态、CPU 使用率和内存情况。下方的进程表有助于定位当前消耗资源较多的进程。
现在打开交互式视图:
top
观察数值的持续更新,找到 %CPU 和 %MEM 列,然后按 q 返回 shell。需要观察资源随时间的变化时,交互式 top 很有用;需要保存输出或交给其他命令处理时,批处理模式更合适。
将聚焦后的进程快照保存为可观察结果:
ps -eo pid,ppid,user,stat,comm --sort=pid > process-snapshot.txt
head -n 5 process-snapshot.txt
启动并查找练习进程
在本步骤中,你将启动一个无害的后台进程,记录它的 PID,并分别使用 ps 和 pgrep 查找它。
末尾的 & 会要求 Shell 在后台运行命令,并立即返回提示符。启动一个持续 5 分钟、可见名称为 labex-worker 的休眠进程:
cd /home/labex/project/process-lab
bash -c 'exec -a labex-worker sleep 300' &
特殊 Shell 变量 $! 包含最近启动的后台进程的 PID。请在启动其他后台命令之前保存它:
worker_pid=$!
echo "$worker_pid" > worker.pid
检查这个指定的进程。选项 -p 用于选择 PID,-o 用于选择字段:
ps -o pid,ppid,user,stat,etime,args -p "$worker_pid"
ETIME 显示已运行时长,ARGS 包含可见的进程名称。使用 pgrep -f 搜索完整命令行;-a 还会同时打印命令行:
pgrep -af labex-worker
pgrep 输出的 PID 应与 worker.pid 中的内容一致。相比对宽泛的进程名称采取操作,使用精确的匹配模式更加安全。
使用信号停止进程
在本步骤中,你将使用 SIGTERM 请求进程正常终止,并仅对专门设计为忽略该请求的进程使用 SIGKILL。
kill 命令向指定 PID 发送信号。如果不明确指定信号,它会发送 SIGTERM,即信号 15。SIGTERM 请求进程有序关闭,并给予进程执行清理工作的机会。
读取工作进程的 PID,并发送 SIGTERM:
cd /home/labex/project/process-lab
worker_pid=$(cat worker.pid)
kill "$worker_pid"
sleep 1
下面预期出现的 ps 失败可以证明该进程已经结束:
ps -p "$worker_pid" || echo "labex-worker stopped after SIGTERM"
现在启动一个受控进程,让它故意忽略 SIGTERM:
bash -c 'trap "" TERM; exec -a labex-stubborn sleep 300' &
stubborn_pid=$!
echo "$stubborn_pid" > stubborn.pid
给新 shell 一点时间来安装信号处理器:
sleep 1
发送 SIGTERM,短暂等待后检查进程:
kill -TERM "$stubborn_pid"
sleep 1
ps -o pid,stat,args -p "$stubborn_pid"
该进程应该仍然存在,因为这个练习进程会忽略 SIGTERM。SIGKILL,即信号 9,无法被捕获或忽略。只有在优雅终止信号无效后,才应使用它:
kill -KILL "$stubborn_pid"
回收已经终止的后台作业。非零状态是预期结果,因此使用 || true 可以让练习流程继续执行:
wait "$stubborn_pid" 2>/dev/null || true
ps -p "$stubborn_pid" || echo "labex-stubborn required SIGKILL"
SIGKILL 不会给进程保存状态或正常释放应用资源的机会,因此只能作为最后手段使用。
kill 针对已知 PID 发送信号。当你需要按名称或完整命令行选择进程时,pkill 可以将匹配与发送信号结合起来。再启动一个命令行具有明显特征的受控进程:
bash -c 'exec -a labex-helper sleep 300' &
helper_pid=$!
echo "$helper_pid" > helper.pid
执行操作前,先确认精确的完整命令匹配:
pgrep -af '^labex-helper 300$'
使用 pkill -f 向这个精确匹配发送 SIGTERM。锚点 ^ 和 $ 可避免训练用模式匹配到无关命令行:
pkill -TERM -f '^labex-helper 300$'
wait "$helper_pid" 2>/dev/null || true
ps -p "$helper_pid" || echo "labex-helper stopped by pkill"
应使用精确的 pkill 模式,并先通过 pgrep 检查匹配结果;过于宽泛的模式可能会停止超出预期的进程。
控制前台和后台作业
在本步骤中,你将暂停一个前台命令,将它恢复到后台运行,再将它切回前台并中断它。
作业控制属于当前交互式 Shell。启动一个具有明显名称的前台休眠进程:
cd /home/labex/project/process-lab
bash -c 'exec -a labex-job sleep 300'
此时终端已被前台进程占用。按下 Ctrl+Z。Shell 会发送停止信号,并返回提示符。
列出当前 Shell 已知的作业。选项 -l 会包含进程 ID:
jobs -l
你应该会看到一个状态为 Stopped 的作业。在后台恢复编号为 1 的作业:
bg %1
jobs -l
此时状态应变为 Running,并且提示符仍然可用。将该作业重新切回前台:
fg %1
按下 Ctrl+C,向前台作业发送中断信号。此时应返回提示符。确认没有残留的练习作业:
pgrep -af labex-job || echo "No labex-job process remains"
完成交互式操作后,创建一个完成标记:
touch job-control.done
对于附着于当前终端的命令,可以使用作业控制。稍后你将使用 nohup 来运行不依赖终端会话的任务。
读取退出状态并运行与终端分离的任务
在本步骤中,你将理解命令退出状态,并运行一个简短的后台任务,使其输出独立于终端显示而保留下来。
每条命令都会返回一个整数状态。零表示成功,非零值表示发生了某种失败。Shell 变量 $? 包含刚刚执行完毕的命令的状态。
运行一个成功的命令,然后立即打印其状态:
cd /home/labex/project/process-lab
true
echo "true status: $?"
结果为 0。现在运行一个找不到路径的命令:
ls missing-path
在其他命令覆盖 $? 之前保存它的状态:
missing_status=$?
echo "missing-path status: $missing_status"
该值应为非零值。保存这两种预期结果:
printf 'success=0\nfailure=%s\n' "$missing_status" > exit-status.txt
nohup 命令会让程序忽略终端挂起信号。末尾的 & 会让程序在后台运行。重定向 < /dev/null 会断开终端输入,而 > nohup.log 2>&1 会将标准输出和标准错误都写入日志:
nohup bash -c 'for item in one two three; do echo "background: $item"; sleep 1; done' < /dev/null > nohup.log 2>&1 &
保存后台进程的 PID,并等待这个短任务完成:
echo $! > nohup.pid
sleep 4
cat nohup.log
你应该会看到三行输出,从 background: one 到 background: three。对于长时间运行的任务,保存的 PID 和日志可以帮助你检查任务进度。
检查最新的内核消息
在本步骤中,你将检查内核消息缓冲区,并保存当前运行内核的版本,作为稳定的参考信息。
内核会将启动、硬件、驱动程序和运行时事件等消息记录到环形缓冲区中。dmesg 用于读取该缓冲区。通常需要管理员权限:
cd /home/labex/project/process-lab
sudo dmesg | tail -n 10
具体消息会因机器和时间而异。重点关注类似时间戳的字段,以及生成每条消息的组件或子系统。
选项 --level 可以按严重级别进行筛选。显示最近的警告和错误:
sudo dmesg --level=err,warn | tail -n 10
没有输出并不表示命令失败,也可能只是当前缓冲区中没有这些级别的消息。搜索最新消息中的常见存储和网络术语:
sudo dmesg | grep -Ei 'disk|filesystem|network|eth' | tail -n 10
同样,结果取决于当前系统。保存 uname -r 报告的内核版本:
uname -r > kernel-version.txt
cat kernel-version.txt
内核消息是证据,而不是自动生成的诊断结论。在决定采取何种操作之前,应将它们与进程状态、服务日志和实际症状结合起来分析。
总结
你识别了 Linux 系统,解读了系统运行时间和负载平均值,并检查了进程 ID、父进程、所有者、状态以及资源快照。你启动并查找了一个命名进程,在使用 SIGKILL 之前先使用了 SIGTERM,还练习了前台和后台作业控制。
你还理解了退出状态,使用 nohup 和明确的日志记录运行了与终端分离的任务,并通过 dmesg 检查了内核消息。这些以观察为先的习惯,是安全排查进程问题的基础,也为后续学习服务、日志和网络诊断做好了准备。



