:安裝、卸載、更新、查詢?nèi)馕? alt=)
1. 先把 apt-get 這套機制想明白再動手敲命令sudo apt-get install這條命令大概是每個碰過 Debian 系系統(tǒng)的人敲得最多的東西。安裝軟件包、卸載軟件包、更新軟件包索引、查詢軟件包信息日常運維里翻來覆去就是這四件事??晌乙娺^太多人用了兩三年遇到無法定位軟件包或者軟件包似乎無效還是一臉茫然最后靠重裝系統(tǒng)解決。問題的根子不在命令記不熟而在于不知道這幾條命令背后到底動了哪些文件、改了哪些狀態(tài)。這篇東西我想把 apt-get 這一套從原理到實操捋一遍重點講安裝、卸載、更新、查詢四條主線順帶把apt-get download、離線安裝、無法定位軟件包的定位思路、半安裝狀態(tài)的修復(fù)這些真實場景里的坑都帶上。適合剛接觸 Linux 的朋友打底子也適合已經(jīng)能跑命令但說不清為什么的人補一下底層邏輯。我個人的看法是apt-get 本身沒那么復(fù)雜復(fù)雜的是它背后那一套「源列表 索引緩存 依賴樹 包狀態(tài)庫」的組合。你把這四個東西的關(guān)系理清絕大多數(shù)報錯都能自己推出來是哪一環(huán)斷了。1.1 apt、apt-get、dpkg、apt-cache 各管哪一攤很多人把 apt、apt-get、apt-cache、dpkg 混著用其實分工很明確理清這一點能省掉很多繞路。dpkg是最底層的包管理工具它只負責(zé)把.deb文件解開、鋪到文件系統(tǒng)上、把安裝狀態(tài)寫進/var/lib/dpkg/status。它不管依賴你給它一個包它就裝缺依賴它也只是報錯不會自動去幫你找。所以直接dpkg -i裝包經(jīng)常出現(xiàn)「依賴關(guān)系沒滿足」的提示。apt-get是 dpkg 之上的一層封裝它做三件 dpkg 不做的事自動解析和下載依賴、從軟件源拉取包、維護依賴關(guān)系數(shù)據(jù)庫。apt-get install時你會看到「下列【新】軟件包將被安裝」那一段就是它在算依賴樹。apt-cache專門負責(zé)查詢不產(chǎn)生任何安裝動作是只看不動的工具。查包、查版本、查依賴、查反向依賴都歸它。apt是后來推出來的統(tǒng)一命令把 apt-get 和 apt-cache 的常用功能揉在一起輸出更友好還帶進度條。但注意apt的 CLI 輸出格式不保證向后兼容寫腳本時官方建議還是用apt-get。所以你在文檔里看到apt install和apt-get install功能基本一樣腳本里優(yōu)先前者以外的那個。一個容易被忽略的點apt-get的所有元數(shù)據(jù)都存在/var/lib/apt/lists/里這是從軟件源下載下來的「包索引」。apt-get update干的事就是刷新這個目錄。而每個包在本地裝了沒有、裝到哪個版本記錄在/var/lib/dpkg/status。這倆文件是兩套東西別混。很多「明明 update 過了還提示找不到包」的問題就是源索引里壓根沒有這個包而不是本地狀態(tài)有問題。1.2 軟件包從哪來源列表、索引緩存與依賴樹的三角關(guān)系把軟件源想象成一個巨大的線上倉庫/etc/apt/sources.list和/etc/apt/sources.list.d/里的文件就是倉庫地址清單。每次apt-get updateapt 會挨個訪問這些地址把每個倉庫的「貨物清單」也就是 Packages 索引文件下載到/var/lib/apt/lists/。這個過程只下載清單不下載任何實際的軟件包本體。這一步很多人誤解以為 update 就是把軟件更新了其實它只是刷新了「貨架目錄」。真正的包體在你執(zhí)行 install 時才會去下載下載的.deb會臨時放在/var/cache/apt/archives/。第三個角色是依賴樹。每個包在自己的元數(shù)據(jù)里寫明了「我需要哪些包」「我和誰沖突」「我替換了誰」。apt 拿到你要裝的包名后會在索引里做一次依賴求解算出需要一并安裝的包集合。如果這個集合里有任何一環(huán)在索引里找不到就會直接失敗報出那個經(jīng)典的E: 無法定位軟件包 xxx。理解了這三者的關(guān)系你就有了排查的固定套路報「無法定位」先懷疑索引里沒有源問題或沒 update報「依賴關(guān)系不滿足」懷疑依賴樹求解失敗通常是源里缺少某個依賴或者本地已有包把依賴卡住了報「軟件包似乎無效」多半是包本身有問題下載不完整、架構(gòu)不對、不是 Debian 格式。Ubuntu 從 24.04 起開始推 deb822 格式的源文件放在/etc/apt/sources.list.d/ubuntu.sources長得像 YAML 的多段結(jié)構(gòu)和老的單行deb http://... jammy main寫法不一樣。兩種格式 apt 都認但改源之前先看清楚你的系統(tǒng)用的是哪種改錯位置等于白改。2. 安裝軟件包從一條 apt-get install 到離線 deb 的完整路徑安裝是 apt-get 最核心的功能也是花樣最多的一塊。從最普通的聯(lián)網(wǎng)安裝到?jīng)]有外網(wǎng)時的離線搬運再到指定版本回退每一種場景的坑都不一樣。這一章我把安裝這條線拆成三段講標(biāo)準(zhǔn)流程、找不到包的排查、離線與指定版本的做法。2.1 標(biāo)準(zhǔn)安裝流程與幾個真正有用的參數(shù)最基礎(chǔ)的用法不用多說sudo apt-get install 包名。但有幾個參數(shù)是真的能救命我按使用頻率排一下。-y是自動確認裝一堆包時不用一直敲回車。寫自動化腳本必加手動裝單個包時我反而建議不加因為你需要看清它準(zhǔn)備裝哪些東西、準(zhǔn)備刪哪些東西。--no-install-recommends值得單獨說。Debian 系把一個包的依賴分成兩類Depends必須和 Recommends推薦。默認 apt 會把 Recommends 也裝上。這在桌面環(huán)境里體驗很好但在服務(wù)器上就是災(zāi)難——你只想裝個curl結(jié)果它順手拉進來幾十個你根本用不到的庫。加這個參數(shù)只裝硬依賴鏡像體積能小一大截。實測下來一個精簡的服務(wù)器環(huán)境加上它初次裝常用工具的磁盤占用能少三到四成。-f是修復(fù)依賴全稱--fix-broken。當(dāng)你因為各種原因讓系統(tǒng)進入「依賴不完整」的狀態(tài)時sudo apt-get install -f會讓 apt 嘗試把缺的補上、把多余的清掉。這個命令我把它當(dāng)急救藥用后面講卸載時還會提到。--dry-run簡寫-s是空跑一遍只打印它「打算做什么」不真正執(zhí)行。升級生產(chǎn)環(huán)境前我一定會先-s跑一次把輸出從頭看到尾確認它不會順手刪掉我依賴的組件。--reinstall用于重裝當(dāng)前已裝的包覆蓋被誤改的文件配置文件一般不動。還有一個很實用的apt-get install ./本地包.deb。從 apt 1.1 開始直接在 install 后面跟一個本地.deb的相對路徑apt 會識別它是本地文件并且自動幫你解析和下載它缺的依賴。這比dpkg -i好太多dpkg -i缺依賴只能報錯還得你自己一條條補。一個真實的安裝記錄長這樣sudo apt-get update sudo apt-get install -y --no-install-recommends openssh-server輸出會先列「將要安裝的軟件包」集合然后是下載體積、磁盤占用估算最后才是實際下載和解包配置。注意到「將要安裝」那段的位置特別關(guān)鍵它是在下載之前打印的這就是給你最后一次反悔的機會。注意apt-get install后面跟的包名是精確匹配或前綴匹配不是模糊搜索。你知道大概叫ssh但不確定全名應(yīng)該先用apt-cache search ssh搜而不是硬猜。猜錯的結(jié)果就是那句讓人抓狂的無法定位軟件包。2.2 無法定位軟件包三步定位法E: 無法定位軟件包 ros-noetic-desktop-full這類報錯是新手最容易卡住的地方。我把它拆成三步按順序排除基本都能找到原因。第一步確認名字對不對。包名區(qū)分大小寫也不接受連字符和空格混用。先搜apt-cache search ros-noetic如果搜出來一堆相關(guān)包但沒有你要的那個說明名字錯了如果一條都沒有往第二步走。有個細節(jié)apt-cache search默認只搜包名和簡介關(guān)鍵詞太寬會刷屏可以配合grepapt-cache search ros | grep -i desktop第二步確認該包所在的軟件源有沒有啟用。這一步是絕大多數(shù)「無法定位」的真正原因。Debian 系把倉庫分了好幾個組件main是官方維護的自由軟件restricted、universe、multiverse在 Ubuntu 上是額外組件。你裝 ROS 這類第三方生態(tài)的包很多時候需要往源里加對應(yīng)的倉庫或者啟用universe??匆谎郛?dāng)前啟用的是哪些grep -rh ^deb /etc/apt/sources.list /etc/apt/sources.list.d/如果universe沒出現(xiàn)而你要裝的包正好在里面那就是它了。第三步確認 update 是不是本地的索引過期了。索引過期不會讓你找不到包但會讓你找到的是舊的包名或舊版本。某個包在新版本里改名了你按老名字裝就會報找不到。所以排查時先跑一次sudo apt-get update有個非常隱蔽的坑update輸出里如果有倉庫 ... 沒有 Release 文件或者404 Not Found說明某個源的地址或代號寫錯了比如把jammy寫成了focal。這種源會被 apt 靜默跳過索引里自然就沒有它里面的包。排查時一定要把 update 的完整輸出讀一遍別只看到?jīng)]報錯就以為成功了。還有一種情況是架構(gòu)不匹配。你在 x86 機器上想裝某個只給 ARM 打包的包索引里本身就不存在這個組合也會報無法定位。用dpkg --print-architecture確認當(dāng)前架構(gòu)。2.3 apt-get download 與離線環(huán)境的搬運方案內(nèi)網(wǎng)機器沒有外網(wǎng)是運維里特別常見的場景。做法很樸素在一臺能上網(wǎng)、系統(tǒng)版本和目標(biāo)機一致的機器上把.deb下載下來拷過去離線安裝。apt-get download專門干這個它只下載不安裝mkdir /tmp/offline cd /tmp/offline apt-get download nginx ls -lh下載完你會得到一個.deb文件。但這里有個坑apt-get download只下載指定的那一個包不下載它的依賴。所以拷過去dpkg -i時極可能缺依賴。兩種應(yīng)對思路思路一把依賴也一起下。先看清楚要裝什么再逐個下載apt-cache depends nginx看輸出的 Depends 那一行把依賴一個個apt-get download下來最后一起拷過去。思路二直接在一臺同樣系統(tǒng)的干凈機器上用apt-get install --download-only下載完整依賴鏈。這個參數(shù)會走完 install 的全部流程把該下的包全都下到/var/cache/apt/archives/但不執(zhí)行安裝sudo apt-get install --download-only -y --no-install-recommends nginx然后把這個目錄里的.deb全部拷到目標(biāo)機在目標(biāo)機里進入該目錄執(zhí)行sudo apt-get install ./*.deb對你沒看錯apt-get install后面可以直接跟通配符展開的一堆本地 debapt 會一起處理依賴順序。這個方法我在內(nèi)網(wǎng)部署里用了很多次比逐個dpkg -i穩(wěn)得多。記得把目標(biāo)機的/var/lib/apt/lists/索引也一起拷過去否則 apt 可能因為沒有索引而無法判斷依賴。如果要下載某個包的指定版本語法是apt-get download 包名版本號版本號從apt-cache policy 包名的輸出里取那個表格里會列出所有可用版本和它們的優(yōu)先級很有參考價值。3. 卸載與清理remove、purge、autoremove 的邊界在哪卸載看起來最簡單實際是四個操作里最容易留下隱患的。我見過有人為了卸一個輸入法執(zhí)行完autoremove之后桌面環(huán)境整個不見了。這一章把卸載的邊界講清楚。3.1 remove 和 purge 到底差在哪一句話總結(jié)remove刪程序保留配置purge連配置一起刪。remove會把包標(biāo)記為「已移除」把程序文件從磁盤刪掉但/etc下的配置文件原地保留。你如果之后重新裝這個包之前的配置還在會直接生效。這在升級、重裝時很有價值。purge是徹底清除程序文件和配置文件一起刪。當(dāng)你確定不再用某個軟件、想留一份干凈的機器時用它。sudo apt-get remove nginx sudo apt-get purge nginx有個特別容易忽視的點很多服務(wù)在運行期間會在/var/log、/var/lib、/home/用戶下生成自己的數(shù)據(jù)文件這些不屬于包管理范圍無論 remove 還是 purge 都不會刪。你要是真想清干凈卸完還得手動去這幾個目錄里找殘留。常見的比如數(shù)據(jù)庫的數(shù)據(jù)目錄、應(yīng)用生成的緩存目錄卸載后依然占著空間。卸載前我習(xí)慣先看一眼這個包到底帶了哪些文件避免刪錯或者刪不干凈dpkg -L 包名 | head -50dpkg -L列出這個包安裝的所有文件路徑輸出太長就配head或者grep /etc只看配置部分。3.2 autoremove 的風(fēng)險控制與殘留依賴apt-get autoremove的作用是把「當(dāng)初作為依賴被自動裝進來、但現(xiàn)在沒有任何包再需要它」的包清掉。聽起來人畜無害實際操作中坑挺深。它靠一個「自動安裝標(biāo)記」來判斷。安裝某個包時作為它依賴被順帶裝進來的包會被打上 auto 標(biāo)記你手動apt-get install xxx裝的包則沒有這個標(biāo)記。autoremove只刪帶 auto 標(biāo)記且不再被依賴的。問題在于標(biāo)記有時候會「失真」。比如某個包最初是被依賴引入的后來你手動用它用得多了或者某個桌面組件的依賴關(guān)系被人為改動過。這時候autoremove給出的清單可能包含你不希望刪的東西。所以我的習(xí)慣是執(zhí)行 autoremove 前一定先空跑一次sudo apt-get autoremove --dry-run把要刪的清單從頭到尾掃一遍??吹揭粋€你還在用、但沒印象是什么時候裝的包先記下來去查apt-cache rdepends 包名rdepends是反向依賴列出「誰依賴我」。如果這個列表是空的說明它確實沒人要了刪掉問題不大如果列表里有你正在用的東西那 autoremove 就是在誤判得用apt-mark manual 包名給它打上手動標(biāo)記把它保護起來。還有一招是給某個包上鎖禁止它被升級或刪除sudo apt-mark hold 包名 sudo apt-mark unhold 包名 sudo apt-mark showhold服務(wù)器上跑著內(nèi)核、數(shù)據(jù)庫這類關(guān)鍵組件時把相關(guān)包 hold 住是很省心的做法。升級時 apt 會明確告訴你「下列軟件包已被保留」不會動它們。3.3 半安裝狀態(tài)與 dpkg 卡死急救三連卸載或安裝中途被強制中斷斷電、CtrlC、磁盤滿包會進入一種「半安裝」?fàn)顟B(tài)文件鋪了一半狀態(tài)庫里的標(biāo)記是iF或者iU而不是正常的ii。這時候任何 apt 操作都會被卡住報一堆「需要重新安裝」或者「依賴未滿足」。急救第一步看當(dāng)前狀態(tài)dpkg -l | grep -v ^ii | head -20正常情況下幾乎所有包都是ii期望安裝、已安裝。出現(xiàn)iF半配置、iU解包未配置就是有問題了。急救第二步讓 dpkg 把沒配完的繼續(xù)配完sudo dpkg --configure -a急救第三步如果 configure 之后還有依賴問題用-f收拾sudo apt-get install -f這三步走下來九成以上的 dpkg 卡死都能恢復(fù)。剩下的那部分通常是磁盤滿了或者/var/lib/dpkg/status真的損壞了。磁盤滿就清一下/var/cache/apt/archives/里的舊包sudo apt-get clean sudo du -sh /var/cache/apt/archives/clean是清空整個下載緩存autoclean是只清過期的舊版本包。定時任務(wù)里我一般用autoclean保留最近的一份重裝時還能直接復(fù)用。注意還有一種非常常見的錯誤是E: 無法獲得鎖 /var/lib/dpkg/lock-frontend說「有另一個進程正在使用它」。這說明后臺有 apt 或 dpkg 在跑最常見的是系統(tǒng)自動更新任務(wù)。別急著 rm 鎖文件先看看是誰在用ps aux | grep -E apt|dpkg | grep -v grep確認沒有活躍進程等它跑完再操作實在卡死了再考慮處理鎖文件。暴力刪鎖帶來的后果可能比等待嚴(yán)重得多。4. 更新與升級update、upgrade、dist-upgrade 的分工更新這塊是四個操作里概念最容易混淆的。新手經(jīng)常把apt-get update和apt-get upgrade當(dāng)成一件事還有人直接用dist-upgrade當(dāng)作萬能升級。這幾條命令的邊界必須掰開講。4.1 update 和 upgrade 為什么必須分開apt-get update只刷新索引不安裝任何東西apt-get upgrade按當(dāng)前索引升級已裝包不刷新索引。兩者職責(zé)分離是 apt 設(shè)計上的一個刻意選擇。為什么分開因為刷新索引有風(fēng)險。你在某個時間點更新了索引然后基于它升級升級過程是可預(yù)期的但如果 update 和 upgrade 混在一起自動執(zhí)行你永遠不知道自己升到的是幾天前還是剛才的新版本。生產(chǎn)環(huán)境里我們會把 update 和 upgrade 分成兩個明確的步驟中間可能還要人工審核升級清單。標(biāo)準(zhǔn)做法是sudo apt-get update sudo apt-get -s upgrade # 先空跑看一眼 sudo apt-get upgradeapt-get upgrade的特點是保守它不刪除任何已裝的包也不安裝新的包來解決依賴變化。如果某個包升級后需要一個新的依賴而這個依賴當(dāng)前沒裝apt 會放棄升級這個包把它留在kept back列表里。這個行為很安全但代價是有些包會長期升不上去。apt-get dist-upgrade則激進得多。它允許安裝新包、刪除舊包來滿足升級后的依賴關(guān)系。這是它能處理內(nèi)核升級、庫大版本變更這類復(fù)雜情況的原因。名字里的dist指的是「發(fā)行版級」不是讓你跨大版本升級系統(tǒng)這一點很多人理解錯了?,F(xiàn)代 apt 里有個等價的命令apt full-upgrade語義更清楚用法和 dist-upgrade 一樣。命令是否刷新索引是否安裝新包是否刪除包適用場景apt-get update是否否定期刷新獨立執(zhí)行apt-get upgrade否否否保守升級生產(chǎn)環(huán)境apt-get dist-upgrade否是是內(nèi)核/庫大版本變更apt full-upgrade否是是同上apt 新版推薦從這張表能看出來upgrade和dist-upgrade的差別就集中在「能不能裝新包、刪舊包」這兩列。理解這一點你就知道什么時候該用哪個了。4.2 版本鎖定與 hold不想被升級打亂的生產(chǎn)環(huán)境生產(chǎn)環(huán)境最怕的就是「一次無人值守的自動升級把某個組件升掛了」。控制升級范圍的手段主要有兩個hold 和 pinning。hold簡單粗暴直接凍結(jié)某個包的版本sudo apt-mark hold nginx sudo apt-mark unhold nginx被 hold 的包在upgrade和dist-upgrade里都會被跳過。適合內(nèi)核、數(shù)據(jù)庫、關(guān)鍵服務(wù)這類「升級收益小、風(fēng)險大」的包。查看當(dāng)前被鎖的有哪些apt-mark showholdpinning更靈活通過優(yōu)先級控制某個包從哪個源、哪個版本安裝。配置文件放在/etc/apt/preferences.d/Package: nginx Pin: version 1.18.* Pin-Priority: 1001優(yōu)先級超過 1000 表示強制降級到這個版本900 到 1000 之間表示優(yōu)先安裝這個版本但不降級。這個機制在「必須鎖在老版本但又要參與整體升級」的場景里特別有用。老實說pinning 的語法容易寫錯而且排查起來不直觀我一般優(yōu)先用 hold只有 hold 表達不了的場景才上 pinning。升級前還有一個必做的動作看一眼升級歷史。apt 所有操作都記錄在/var/log/apt/history.log出問題回查的時候這個文件是唯一的線索。它記著什么時候、哪個用戶、執(zhí)行了什么命令、裝刪了哪些包。養(yǎng)成升級前先tail一下的習(xí)慣能幫你回憶上一次動過什么。4.3 部分升級與內(nèi)核更新時的注意事項在內(nèi)核、顯卡驅(qū)動這類組件上做升級有幾個點必須提前知道。內(nèi)核更新后不會自動生效。升級會裝上新內(nèi)核但當(dāng)前運行的內(nèi)核還是舊的需要重啟才切換。所以升級完先別急著關(guān)終端確認一下uname -r dpkg -l | grep linux-image | head對比當(dāng)前運行的內(nèi)核版本和已安裝的最新內(nèi)核版本如果不一樣說明需要重啟。舊內(nèi)核不會自動刪。多次升級后/boot分區(qū)會被舊內(nèi)核塞滿導(dǎo)致下次裝新內(nèi)核時報「空間不足」。定期清理注意別刪當(dāng)前正在用的那個dpkg -l | grep linux-image sudo apt-get autoremove --purgeautoremove --purge會自動把標(biāo)記為不再需要的舊內(nèi)核連同配置一起清掉。不過在容器化的環(huán)境里這個操作要格外小心容器通常用的是宿主機的內(nèi)核容器內(nèi)部不應(yīng)該有內(nèi)核包。庫的大版本變更用 upgrade 是做不動的。比如某個 C 庫從 5 升到 6很多包依賴關(guān)系跟著變upgrade會大量kept back。這時候必須用dist-upgrade或者full-upgrade并且在執(zhí)行前把-s的輸出仔細讀一遍重點看「將要刪除」那一列確認刪掉的都是可以刪的。提示升級前如果你機器上有正在運行的關(guān)鍵服務(wù)先做好配置備份。apt 在升級某些服務(wù)時如果檢測到你改過配置文件會停下來問你「配置文件要保留還是替換」這個交互式提示在腳本里會因為無輸入而卡住。想避免可以在命令前加DEBIAN_FRONTENDnoninteractive但記得提前想好自己的策略。5. 查詢與信息檢索用 apt-cache 和 dpkg 解決問題查詢這塊是很多人跳過的一環(huán)覺得裝得上就行。但真正遇到問題時能不能快速查清楚「這個包裝沒裝」「缺的依賴誰提供」「這個文件屬于哪個包」決定的是一小時還是十分鐘解決。5.1 查已裝、查可裝、查版本與依賴先把常用的查詢命令按用途分一下。查已裝的包dpkg -l # 列出所有包及狀態(tài) dpkg -l | grep nginx # 找特定包 apt list --installed # apt 版輸出格式不同dpkg -l的輸出前面那兩三個字母是狀態(tài)碼ii是正常其他都是異常。我最常用的是配grep -v ^ii一把撈出所有異常的包。查一個包的詳細信息apt-cache show 包名 # 全部可用版本的完整元數(shù)據(jù) apt-cache policy 包名 # 已裝版本、可用版本、源優(yōu)先級apt-cache policy是我最推薦的一個命令一個輸出就能看到四個關(guān)鍵信息本地裝的是哪個版本、有哪些候選版本、每個版本來自哪個源、源的優(yōu)先級。裝指定版本前必看。查依賴關(guān)系apt-cache depends 包名 # 我依賴誰 apt-cache rdepends 包名 # 誰依賴我rdepends在卸載分析里的價值特別高。想刪一個不確定用途的包先看反向依賴如果輸出里有你正在用的東西說明不能隨便刪。查可裝的包apt-cache search 關(guān)鍵詞 apt-cache search --names-only 關(guān)鍵詞 # 只在包名里搜結(jié)果更準(zhǔn) apt-cache pkgnames | grep 關(guān)鍵詞apt-cache search不加限制的話會搜包名和描述結(jié)果經(jīng)常上百條。--names-only只在包名里匹配精確度高一截。5.2 根據(jù)文件反查包dpkg -S 與 apt-file「這個文件是哪個包裝的」是排查系統(tǒng)問題的經(jīng)典需求。比如你發(fā)現(xiàn)某個二進制文件不知道從哪來的或者某次誤改了文件想恢復(fù)知道它屬于哪個包就能直接重裝覆蓋。如果文件已經(jīng)裝在系統(tǒng)上用dpkg -Sdpkg -S /usr/bin/ssh dpkg -S $(which python3)-S是--search的簡寫它查的是本地文件和你已裝包的文件清單的對照表。輸出會告訴你這個路徑屬于哪個包。如果報「找不到」說明這個文件不屬于任何包管理安裝的包可能是手動編譯裝上去的。反過來的需求是某個包還沒裝但我想知道它裝了哪些文件。dpkg -L只能查已裝的沒裝的用apt-filesudo apt-get install apt-file sudo apt-file update apt-file list 包名 apt-file search 文件名 # 反查這個文件在哪個包里apt-file需要單獨安裝并且要更新自己的索引索引比 apt 的大不少但換來的是「裝之前就能知道包里有什么」的能力排查「某個命令屬于哪個包」時非常好使。dpkg -S和apt-file search的區(qū)別值得記一下前者查已裝索引來自/var/lib/dpkg/info/后者查可裝索引來自遠程下載的Contents文件。兩個查詢的對象完全不同遇到「找不到」時先想清楚該用哪個。6. 常見報錯排查速查表與實操心得前面講了原理和流程這一章把高頻報錯集中列一下再補一些文檔里不會寫、但踩過才知道的細節(jié)。6.1 常見報錯與對應(yīng)處理報錯信息大概率原因處理方向E: 無法定位軟件包 xxx源未啟用、名字錯、索引過期先apt-cache search再查源最后apt-get updateE: 軟件包似乎無效下載不完整、架構(gòu)不符、非 deb 格式清除緩存重下dpkg --print-architecture核對架構(gòu)依賴關(guān)系不滿足未安裝源里缺依賴或本地包卡依賴apt-get install -f修復(fù)--no-install-recommends減少牽連無法獲得鎖 /var/lib/dpkg/lock-frontend有 apt 進程在跑ps aux確認進程等它結(jié)束dpkg 被中斷必須重新運行上次操作被強殺dpkg --configure -a再apt-get install -f下列軟件包被保留upgrade 無法滿足新依賴改用dist-upgrade或查清是哪個包卡住磁盤空間不足/boot 或 / 滿舊內(nèi)核堆積apt-get autoclean、autoremove --purge這張表建議存下來。遇到報錯先在上面找對應(yīng)的行比盲搜強。6.2 我踩過的坑和幾條實用心得第一條別在索引沒更新時下結(jié)論。我有一次在內(nèi)網(wǎng)機器上排查一個裝不上的包翻了半天源配置最后發(fā)現(xiàn)是那臺機器三個月沒update過源里的包名早就改了。現(xiàn)在我處理任何「裝不上」的問題第一步永遠是sudo apt-get update把這條路先堵死。第二條腳本里別用apt用apt-get。apt的輸出格式官方明確說不保證兼容你今天寫的grep 已經(jīng)是最新版明天可能就匹配不上了。寫自動化腳本時老老實實apt-get加-y輸出穩(wěn)定。第三條看清楚「將要刪除」那一列再回車。dist-upgrade和autoremove都會刪包apt 在確認前會明確列出來。養(yǎng)成習(xí)慣掃一眼有沒有你正在依賴的東西。這一點在服務(wù)器上比在個人電腦上重要得多。第四條準(zhǔn)備一份離線包的應(yīng)急清單。網(wǎng)絡(luò)中斷、源地址變更、證書過期這些都不影響你手上已經(jīng)下好的.deb。我習(xí)慣把幾臺關(guān)鍵服務(wù)器常用的包用--download-only下好放進一個目錄配合版本號和架構(gòu)標(biāo)注關(guān)鍵時刻能救命。第五條知道去哪看日志。問題發(fā)生時最直接的證據(jù)都在日志里/var/log/apt/history.log記錄操作歷史/var/log/apt/term.log記錄終端輸出/var/log/dpkg.log記錄 dpkg 層面的文件變動。三份日志對照著看能還原絕大部分操作現(xiàn)場。很多人只知道重裝系統(tǒng)是因為沒意識到證據(jù)其實一直都在。第六條源文件的修改要留痕。改/etc/apt/sources.list之前先復(fù)制一份備份命名加上日期。半年后你回來排查問題有了這個備份就能立刻知道當(dāng)時改了什么。我吃過這個虧改過源又沒記結(jié)果一個詭異的依賴問題查了兩天。第七條容器里別把 apt 當(dāng)萬能工具。容器鏡像講究的是體積apt-get install和apt-get clean要在同一條RUN指令里完成否則下載緩存在上一層鏡像里刪不掉體積下不來。寫法上apt-get update apt-get install -y --no-install-recommends 包名 \ rm -rf /var/lib/apt/lists/*把索引也一起刪掉能再省出一部分空間。這個組合在構(gòu)建精簡鏡像時幾乎是標(biāo)配。真正把一個包管理工具用熟靠的不是背命令而是形成一套固定的排查順序先 update 看索引再 search 確認名字再 policy 看版本和來源最后才動手裝或卸。這個順序養(yǎng)成了你會發(fā)現(xiàn)以前那些「玄學(xué)問題」其實每一步都有確定的答案。