Linux 软件包管理与作业控制 – 实践练习
Source: Linux Package Management – Job Control Practice Exercises (Dev.to)
请提供您希望翻译的完整文本(除代码块和 URL 之外),我将为您翻译成简体中文并保留原有的格式。
Exercise 1 – Job vs Process
Goal
了解 Bash 中 job(作业)与 process(进程)的区别,以及为什么管道算作单个作业。
Background
- Process – 正在运行的程序实例,由 PID 标识。
- Job – Bash 一起管理的一个或多个进程的集合(例如管道)。
- Bash 为每个作业分配一个 job ID(
%1、%2、…),可以使用作业控制内建命令(fg、bg、jobs、kill)来引用它们。
Source: …
第 1 部分 – Bash 作业与进程控制
1️⃣ 列出当前作业
jobs
- 如果没有显示任何作业,请先启动一些后台任务(见第 2 步)。
2️⃣ 启动一些后台作业
# 简单的 sleep 命令
sleep 60 & # 作业 %1
sleep 120 & # 作业 %2
# 一个管道(算作单个作业)
yes | head -n 1000000 > /dev/null &
- 使用
jobs -l验证作业,可看到 作业 ID 和 PID。
3️⃣ 将作业切换到前台
fg %1 # 将 %1 替换为想要的作业 ID
- 注意,此时命令会占用终端,直到它完成或你将其挂起(
Ctrl+Z)。
4️⃣ 挂起前台作业并在后台恢复它
# 当作业在前台运行时,按 Ctrl+Z
# Bash 会报告类似信息: [1]+ Stopped sleep 60
bg %1 # 在后台恢复被挂起的作业
- 使用
jobs -p只列出后台作业的 PID。
5️⃣ 终止作业
kill %2 # 向作业 %2 发送 SIGTERM
kill -9 %2 # 若未正常退出,则强制杀死
- 用
jobs确认作业已消失。
6️⃣ 验证管道是单个作业
# 在后台启动管道
{ yes | head -n 500000 > /dev/null; } &
jobs -l
- Bash 会报告 一个 作业 ID,尽管管道会创建两个进程(
yes和head)。这两个 PID 都列在同一个作业下。
摘要检查清单
- 使用
jobs和jobs -l列出作业。 - 使用
&启动后台作业。 - 使用
fg将作业带到前台。 - 用
Ctrl+Z暂停并用bg恢复。 - 使用
kill终止作业。 - 注意管道算作单个作业。
进一步阅读
- Bash 参考手册 – Job Control
man bash→ JOB CONTROL 部分man kill,man fg,man bg,man jobs
Exercise 1 – Job vs Process (Foreground job)
Goal
了解 job(作业)与 process(进程)的区别,以及为什么管道算作单个作业。
Task
ping -c 5 google.com | wc -l
Observe
- 创建了两个进程:
ping和wc。 - 创建了一个作业:整个管道被视为单个命令。
Why it matters
- Bash 作业控制针对 作业 而不是单个进程进行操作。
- 了解这一点有助于在调试或管理管道时做出正确判断。
Exercise 2 – 前台作业阻塞 Shell
任务
ping google.com
运行该命令,然后尝试输入另一条命令。
观察
- Shell 被阻塞。
- 所有键盘输入都发送到
ping进程。
停止方法
按 Ctrl + C。
生产相关性
长时间运行的前台命令会阻塞自动化脚本并阻止后续命令的执行。
练习 3 — 后台作业 (&)
任务
ping -c 10 google.com &
观察
- Shell 立即返回提示符。
- ping 输出继续异步出现。
检查作业列表
jobs
为什么重要
在后台运行命令而未妥善处理输出,可能会使终端或日志文件变得杂乱。根据需要使用作业控制(jobs、fg、bg、kill)或重定向输出。
练习 4 – 重定向后台输出
任务
ping -c 10 google.com > ping.log &
观察
- 没有终端噪音。
- 输出已安全地捕获到
ping.log中。
生产环境相关性
为后台作业重定向输出是生产环境中的标准做法。
练习 5 — 使用 /dev/null
任务
ping google.com > /dev/null &
观察
- 命令的输出会被完全丢弃。
原因
在健康检查或保持活跃的脚本中很方便,因为你不需要任何输出。
练习 6 — 工作列表
任务
jobs
启动多个作业
ping google.com > /dev/null &
ping bing.com > /dev/null &
观察
作业 ID([1]、[2]、…)出现。
练习 7 – 将作业置于前台 (fg)
任务
fg %1
停止方法
按 Ctrl + C。
关键规则
只有 前台作业 会接收键盘信号。
练习 8 — 挂起作业(Ctrl + Z)
任务
ping google.com
# press Ctrl+Z
jobs
观察
作业状态:已停止。
练习 9 — 在后台恢复作业 (bg)
任务
bg %1
jobs
观察
- 作业再次运行。
- 它仍然不接受键盘输入。
练习 10 — 终止作业
任务
kill %1
强制终止
kill -9 %1
生产相关性
安全地终止失控的作业。
练习 11 — wait 命令
任务
ping -c 5 google.com > /dev/null &
ping -c 5 bing.com > /dev/null &
wait
echo "All jobs finished"
观察
echo 仅在两个 ping 命令完成后才运行。
原因
演示在 shell 脚本中使用 wait 对并行执行进行控制。
练习 12 – wait -n(任意作业完成)
任务
ping -c 10 google.com > /dev/null &
ping -c 3 bing.com > /dev/null &
wait -n
echo "One job finished"
练习 13 — 使用终端响铃进行通知
任务
ping -c 5 google.com > /dev/null &
wait
tput bel
echo "Download complete"
为什么?
在长时间运行的手动任务完成时提供可听的提示。
Exercise 14 — nohup 在注销后仍然存活
Task
nohup ping -c 30 google.com > nohup.out &
exit
- 再次登录。
- 验证 ping 进程仍在运行:
ps aux | grep ping
Observation
ping 作业在你注销后仍然继续运行。
Production Relevance
对于必须在用户会话结束后仍保持运行的远程服务器操作非常有用(例如,长时间运行的脚本、后台服务)。
练习 15 — 父进程更改(重新父化)
任务
ps -o pid,ppid,cmd -p <pid>
观察
注销后,父 PID 会变为 1(init 进程)。
第 2 部分 — RPM(低层包管理)
练习 16 – 在不安装的情况下检查 RPM
rpm -qpl zsh*.rpm
列出该软件包将会安装的文件。
练习 17 — 手动安装 RPM
sudo rpm -i zsh*.rpm
不会执行依赖关系解析。
练习 18 – 删除 RPM
sudo rpm -e zsh
演示了仅使用 RPM 在生产环境中可能带来的风险(不会自动处理依赖或配置文件)。
第3部分 — DNF核心使用
练习19 — 搜索软件包
dnf search links
练习20 — 安装及其依赖
sudo dnf install links
练习21 — 删除软件包
sudo dnf remove links
练习22 — 仓库感知
dnf info neofetch
显示哪个仓库提供了该软件包。
第 4 部分 — 软件仓库 (BaseOS, AppStream, …)
练习 23 – 列出仓库
dnf repolist
练习 24 – 启用 CRB
sudo dnf config-manager --set-enabled crb
练习 25 – 启用 EPEL
sudo dnf install epel-release
安装 htop
sudo dnf install htop
第 5 部分 – 依赖分析
练习 26 – 包提供了什么
dnf repoquery --provides bash
练习 27 – 包需要什么
dnf repoquery --requires bash
练习 28 – 谁需要该包
dnf repoquery --whatrequires bash
练习 29 – 弱依赖(推荐)
dnf repoquery --recommends gimp
练习 30 – 安装时不包含弱依赖
sudo dnf install gimp --setopt=install_weak_deps=False
练习 31 – 反向弱依赖(补充)
dnf repoquery --what-supplements langpacks-de
第 6 部分 — 依赖移除的风险
练习 32 — 依赖自动移除问题
# Install Matplotlib (which pulls in NumPy)
sudo dnf install python3-matplotlib
# Verify NumPy works
python3 -c "import numpy"
# Remove Matplotlib
sudo dnf remove python3-matplotlib
# Verify NumPy again
python3 -c "import numpy"
在移除 python3-matplotlib 后,应用会崩溃,因为 numpy 是作为 依赖 安装的,并随之被自动删除。
练习 33 — 使用 dnf mark install 进行修复
# Install NumPy explicitly
sudo dnf install python3-numpy
# Mark it as a manually‑installed package so it isn’t auto‑removed
sudo dnf mark install python3-numpy
# Now remove Matplotlib safely
sudo dnf remove python3-matplotlib
通过将 python3-numpy 标记为手动安装的包,即使其依赖的包 (python3-matplotlib) 被移除,它仍会保留在系统中。
Part 7 – 更新、降级和版本锁定
练习 34 – 系统升级
sudo dnf upgrade
练习 35 – 降级软件包
-
列出该软件包的所有可用版本:
dnf list python3 --showduplicates -
降级到所需版本(将
<VERSION>替换为您想要的确切版本号):sudo dnf downgrade python3-<VERSION>
练习 36 – 临时升级排除
sudo dnf upgrade --exclude=python3*
第 8 部分 – 自动更新
练习 37 – 启用自动更新
-
安装
dnf-automatic软件包:sudo dnf install dnf-automatic -
启用并启动计时器:
sudo systemctl enable --now dnf-automatic.timer
练习 38 – 配置仅安全更新
-
打开配置文件进行编辑:
sudo vi /etc/dnf/automatic.conf -
设置以下选项(将它们放在相应的节下,例如
[commands]):upgrade_type = security apply_updates = yes
注意: 新设置将在下次计时器运行时生效。若要立即应用更新,可运行
sudo dnf-automatic --upgrade。
Source: …
第9部分 — DNF 模块
练习 39 – 列出模块
dnf module list
练习 40 – 启用 Node.js 流
sudo dnf module enable nodejs:18
sudo dnf upgrade
node --version
练习 41 – 安装模块配置文件
sudo dnf module install nodejs:18/development
练习 42 – 移除模块配置文件
sudo dnf module remove nodejs:18/development
练习 43 – 禁用并重置模块
sudo dnf module disable nodejs
sudo dnf module reset nodejs
第10部分 — 依赖冲突调试
练习44 — 损坏的 RPM 安装
sudo dnf install https://example.com/foreign.rpm
分析
使用以下命令识别缺失的依赖项:
dnf repoquery --whatprovides <package-name>
第11部分 — Snap 包
练习 45 – 安装 Snap
sudo dnf install snapd
sudo systemctl enable --now snapd.socket
练习 46 – 通过 Snap 安装 Firefox
sudo snap install firefox
snap run firefox
练习 47 – 比较版本
firefox --version
snap run firefox --version
Snap 版 Firefox 更新。