进程、资源、后台运行与日志
前置知识:用户、权限及环境变量
本章目录
本章学习目标
- 区分 PID、作业号与退出状态
- 管理自己启动的后台任务
- 解释日志、资源与 nohup 的用途边界
进程与 Shell 作业
进程是运行中的程序实例,PID 是操作系统标识。Shell 作业号是当前 Shell 的管理编号,只在那个会话有效。command & 在后台启动,$! 给出最近后台进程 PID,jobs 列当前 Shell 的作业,ps 查看进程。后台意味着 Shell 不等待,不保证任务在关闭终端后继续,也不保证输出自动存到日志。
数据处理任务通常需要记录 PID、开始时间、参数和输出位置。仅观察一个进程还活着不能认定任务正常,它可能卡在网络或等待输入。仅看日志最后一句也不能确定成功,退出状态与预期产物需要一起检查。课程只启动自己的 sleep,避免查看或停止用户真实训练进程。
等待与信号的逐步演算
sleep 20 & 后立即保存 child_pid=$!,当前脚本可以继续工作。wait "$child_pid" 等待该子进程并获得状态;wait 通常只能等待本 Shell 的子进程,不能随意接管其他会话 PID。kill 默认发送 TERM 信号,表示请求结束,不是直接删除文件。KILL 无法被捕获,应作为最后手段而不是默认习惯。
示例查看自己创建的 PID,再发送 TERM 并 wait 回收。被信号终止的 wait 通常返回非零,脚本用条件分支记录,这是预期演示而不是故障。退出 trap 保证脚本提前失败时也清理自建 sleep。不要用 killall python 或 pkill 模糊名称,可能把其他训练和分析进程一起结束。
资源观察与性能解释
Ubuntu 中 top 可观察 CPU 与内存,free -h 看内存,df -h 看文件系统空间,du -sh 查看目录占用。CPU 百分比高不等于程序正确,低也可能是 I/O 等待;内存中的缓存不能直接当作泄漏。大 CSV 处理应同时考虑峰值内存、读取速度和输出空间。查看命令本身不应把整个磁盘重复扫描到失去响应。
/usr/bin/time -v 可以测一次程序的资源信息,但不同平台工具选项不同,不能把 Git Bash 的结果直接写成 Ubuntu 验证。重复运行会受文件缓存、其他任务和随机种子影响。比较两种实现时先确认结果一致,再在相似负载与输入上测量,报告环境和限制,而不只写一个速度倍数。
后台日志、nohup 与可追溯性
nohup python job.py >job.log 2>&1 & 是常见远程运行形式:忽略挂断信号,合并输出到文件并后台启动。但 nohup 不是服务管理、故障重启或持久会话系统,机器重启后不会自动恢复。日志应包括开始、结束、错误和版本,文件可能缓冲而没有实时刷新,不能把短暂无输出当成停机。
本章不执行真实远程任务,也不修改进程调度。课程产物与日志放指定输出目录,并记录完成状态;只有自己创建的 PID 才可停止。实际长任务还要考虑检查点、恢复、磁盘满和异常退出。Linux 命令只是运行控制的一部分,程序本身的异常处理和可重复输出同样决定任务是否可信。
执行环境与验证边界
本课程命令使用 GNU 工具和 Bash 语法。Windows PowerShell 中的变量、引号、重定向和程序解析与 Bash 并不相同;请在 WSL 的 Ubuntu 终端运行示例,不能把整段 Bash 直接粘贴进 PowerShell。Git Bash 可以运行部分命令,但进程、权限、用户和工具选项可能不同;在 Git Bash 上成功不能证明已经在 Ubuntu 上验证。安装 WSL 是读者的环境准备步骤,课程脚本不会替读者更改系统配置。
每个可运行示例从脚本自身位置确定课程根目录,并只在课程 outputs/linux 子目录或自己建立的临时目录操作。首次运行前先阅读脚本,辨认哪些语句读取、哪些写入、哪些清理。检查路径中有空格时是否仍能运行,检查失败后是否返回非零状态,检查重新运行是否得到同样的结果。对生产数据进行操作时不能照搬练习目录的删除命令,必须重新确认目标范围。
Linux 学习应关注输入、输出、错误输出和退出状态这四件事。标准输出用于数据,标准错误用于诊断,退出状态用于让上层脚本判断成功与否;三者不能互相替代。把手工执行过程写成小脚本后,再通过独立目录重复运行一次。遇到差异时记录操作系统、Bash 和工具版本,把环境限制和代码错误区分开,这比无条件写下“全部通过”更有用。
完整示例与实际输出
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
WORK="$ROOT/outputs/linux/linux-process"
mkdir -p -- "$WORK"
sleep 20 &
child_pid=$!
cleanup() {
if [[ -n "${child_pid-}" ]]; then
kill "$child_pid" 2>/dev/null || true
wait "$child_pid" 2>/dev/null || true
fi
}
trap cleanup EXIT
printf 'started own child pid=%s\n' "$child_pid"
if ps -p "$child_pid" -o pid=,comm= 2>/dev/null; then
printf '%s\n' 'GNU ps inspection succeeded'
else
printf '%s\n' '当前 ps 不支持 GNU -o;用 kill -0 验证自建子进程仍存在,Ubuntu ps 输出待验证'
kill -0 "$child_pid"
fi
kill "$child_pid"
if wait "$child_pid"; then
printf '%s\n' 'child exited normally'
else
status=$?
printf 'own child terminated, wait status=%s\n' "$status"
fi
child_pid=''
printf '%s\n' 'only the child created by this script was stopped' > "$WORK/process.log"
cat "$WORK/process.log"
实际运行通过Git Bash/MSYS on Windows compatibility run; Ubuntu and remote behavior not verified.
started own child pid=79 当前 ps 不支持 GNU -o;用 kill -0 验证自建子进程仍存在,Ubuntu ps 输出待验证 own child terminated, wait status=143 only the child created by this script was stopped
五道自测:先回答,再核对
01 · PID 与 jobs 作业号一样吗?
查看提示
系统与会话。
查看参考答案
不一样,PID 属操作系统,作业号属于当前 Shell 会话。
02 · & 会自动写日志吗?
查看提示
输出仍去哪?
查看参考答案
不会,需要显式重定向;默认输出仍可能进入终端。
03 · $! 表示什么?
查看提示
最近后台任务。
查看参考答案
最近后台启动的进程 PID,应立即保存。
04 · kill 默认是强制不可捕获吗?
查看提示
TERM 与 KILL。
查看参考答案
不是,默认 TERM 可被处理;KILL 不可捕获。
05 · nohup 能在机器重启后恢复任务吗?
查看提示
挂断与重启不同。
查看参考答案
不能,只处理挂断影响,恢复需额外机制。
两项动手任务
任务 1 · 启动自己的短 sleep,wait 后打印成功。
提示
保存 PID 并等待。
完整参考解答与检查方式
sleep 1 & child_pid=$!; if wait "$child_pid"; then printf '%s\n' done; else status=$?; printf 'failed: %s\n' "$status" >&2; fi 仅管理当前 Shell 创建的子进程,不使用模糊进程名称。任务 2 · 让自己的后台子 Shell 输出两行到临时日志,再读取。
提示
等它完成后读。
完整参考解答与检查方式
tmp_file=$(mktemp); bash -c 'printf "start\n"; sleep 1; printf "end\n"' >"$tmp_file" 2>&1 & child_pid=$!; wait "$child_pid"; cat "$tmp_file"; rm -f -- "$tmp_file" 完成日志含 start 与 end;wait 确保产物已经写完。官方资料与掌握状态
完成两项任务后,按独立完成程度记录。状态会尽量保存在当前浏览器,可导出备份。
动手任务记录
掌握状态与复习
关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。
记录尽量保存在当前浏览器,建议定期导出备份。