apt-get 命令詳解:update、install、remove 與 apt 的區別
apt-get 是 Debian 和 Ubuntu 上安裝、升級、解除安裝 .deb 軟體包的命令列工具。最常用的組合是先 apt-get update 重新整理軟體包列表,再 apt-get install 安裝;解除安裝用 remove(保留配置)或 purge(連配置一起刪)。apt 與 apt-get 用的是同一套引擎,互動操作用 apt 更順手,指令碼里用 apt-get 更穩妥。
apt-get 是 Debian 系發行版(Debian、Ubuntu 及其衍生版)的軟體包管理命令,屬於 APT 工具集。它負責從軟體源下載 .deb 包、自動處理依賴,再交給底層的 dpkg 完成安裝和解除安裝。日常用法就三步:先重新整理軟體包列表,再安裝或解除安裝。
sudo apt-get update # 重新整理軟體包列表,不會升級任何軟體
sudo apt-get install -y nginx # 安裝 nginx 及其依賴,-y 表示自動確認
sudo apt-get remove nginx # 解除安裝程式,/etc/nginx 下的配置保留
子命令對照表:update、upgrade、install、remove 各做什麼
| 命令 | 作用 | 會裝新包嗎 | 會刪包嗎 | 典型場景 |
|---|---|---|---|---|
update |
從軟體源下載最新的軟體包列表,不升級任何軟體 | 否 | 否 | 每次安裝、升級之前 |
upgrade |
把已安裝的包升級到列表裡的新版本 | 否,需要新依賴的包會被“保留”不升級 | 否 | 日常打安全補丁 |
dist-upgrade |
在 upgrade 的基礎上處理依賴變化,需要時裝新包、刪衝突的包 | 是 | 是 | 核心升級、依賴關係變化 |
install 包名 |
安裝或升級指定的包及其依賴 | 是 | 很少,只在衝突時 | 裝軟體 |
install -f |
修復依賴關係不完整的系統(--fix-broken) |
是 | 可能 | dpkg 裝包後缺依賴 |
install --reinstall 包名 |
重新安裝同一版本 | 否 | 否 | 程式檔案被誤刪或改壞 |
remove 包名 |
解除安裝,保留配置檔案 | 否 | 是 | 暫時不用,以後可能再裝 |
purge 包名 |
解除安裝,並刪除配置檔案 | 否 | 是 | 徹底不要了,或想恢復預設配置重灌 |
autoremove |
刪除當初作為依賴自動裝上、現在已經沒有包需要的軟體 | 否 | 是 | 解除安裝軟體之後、清理舊核心 |
download 包名 |
只把 .deb 下載到當前目錄,不安裝,不下載依賴 | 否 | 否 | 離線安裝、檢視包裡有什麼 |
clean / autoclean |
清空 /var/cache/apt/archives 裡下載過的 .deb;autoclean 只刪已經無法再下載的舊版本 |
否 | 否 | 釋放磁碟空間 |
幾個常用的全域性引數:-y 自動回答 yes;-s 只模擬、不真正執行,用來預先看會發生什麼;-q 減少輸出,適合寫進日誌;--no-install-recommends 只裝必需的依賴,不裝“推薦”的附帶軟體,伺服器上用它能少裝不少東西。
upgrade 和 dist-upgrade 的區別
在 Ubuntu 上執行 apt-get upgrade,經常看到這樣的輸出:
The following packages have been kept back:
linux-generic linux-headers-generic linux-image-generic
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
原因是新核心要以一個新的包名(包名裡帶著新的版本號)安裝進來,而 upgrade 的規則是絕不裝新包、絕不刪包,只能把這幾個元包“保留”在原版本。dist-upgrade 沒有這個限制,會把新核心裝上;直接 apt-get install linux-generic 也能達到同樣的效果。Ubuntu 還有分階段推送(phased updates)機制,部分更新會先推給一部分機器,沒輪到的機器上這些包也會顯示為暫不升級,過幾天自然會升級,不必處理。
因為 dist-upgrade 會刪包,執行前先模擬一遍,看看要刪的是什麼:
apt-get -s dist-upgrade | grep '^Remv' # 模擬執行,只列出將被刪除的包
另一個常見誤解:名字裡有 dist,但 dist-upgrade 不會把 Ubuntu 22.04 升到 24.04,它只在當前軟體源的範圍內升級。跨大版本升級,Ubuntu 用 do-release-upgrade,Debian 按對應版本發行說明裡的步驟先改軟體源再升級。
apt 和 apt-get 的區別
apt 是 APT 1.0(2014 年)起加入的命令,把 apt-get 和 apt-cache 裡最常用的功能合到一起,並改進了互動體驗。兩者底層是同一個庫、同一份軟體源配置、同一個下載快取和同一個 dpkg 資料庫:用 apt 裝的包,可以用 apt-get 解除安裝,反過來也一樣。
| 對比項 | apt | apt-get |
|---|---|---|
| 面向誰 | 在終端裡手動操作的人 | 指令碼和自動化工具 |
| 輸出 | 有進度條和顏色,update 後提示有多少包可以升級 | 純文字,格式多年保持穩定 |
| 在指令碼里使用 | 輸出被重定向時會列印 WARNING: apt does not have a stable CLI interface. Use with caution in scripts. |
沒有這類警告 |
| upgrade 的行為 | apt upgrade 需要時會安裝新的依賴包,但仍然不刪包 |
apt-get upgrade 不裝新包 |
| 下載的 .deb | 預設在安裝成功後刪除 | 保留在 /var/cache/apt/archives |
| 查詢 | apt search、apt show、apt list --installed、apt list --upgradable |
查詢要用 apt-cache search、apt-cache show、apt-cache policy |
| 對應關係 | apt full-upgrade |
apt-get dist-upgrade |
選擇很簡單:自己登入上去裝個軟體、看看有什麼可升級,用 apt;寫進初始化指令碼、定時任務、自動化工具裡的,用 apt-get,它的引數和輸出格式不會隨版本變來變去,指令碼解析起來更可靠。
安裝軟體:指定版本、本地 .deb 與 install -f
先看清楚要裝的是哪個版本、來自哪個源:
apt-cache policy nginx # Installed 是已裝版本,Candidate 是將要安裝的版本,下面列出各個來源
apt-cache madison nginx # 列出軟體源裡所有可裝的版本
需要固定版本時,在包名後面加 =版本號,版本號照 madison 輸出的第二列原樣填寫,然後鎖定,防止下次升級被順手升上去:
sudo apt-get install nginx=1.24.0-2ubuntu7 # 範例版本號,以 madison 的實際輸出為準
sudo apt-mark hold nginx # 鎖定,upgrade 時跳過它
apt-mark showhold # 檢視哪些包被鎖定
sudo apt-mark unhold nginx # 解除鎖定
廠商單獨提供的 .deb(監控 agent、陣列卡管理工具之類)有兩種裝法。用 dpkg 裝,它不管依賴,缺什麼就報錯,留下一個“裝了一半”的包:
sudo dpkg -i ./agent_2.1.0_amd64.deb
# 缺依賴時報 dependency problems prevent configuration of agent
sudo apt-get install -f # 補裝缺失的依賴,並完成這個包的配置
更省事的做法是直接讓 apt-get 裝本地檔案,依賴一併解決。注意路徑要帶 ./ 或寫成絕對路徑,否則 apt-get 會把它當成軟體源裡的包名去找:
sudo apt-get install ./agent_2.1.0_amd64.deb
apt-get install -f 不是萬能的。它的目標是讓依賴關係恢復一致,如果某個包需要的依賴在當前系統上根本裝不上(比如 .deb 是給別的發行版版本打的),它給出的“修復”方案就是把這個包,甚至別的包一起刪掉。按 Y 之前,一定看清 The following packages will be REMOVED 下面列了什麼。
解除安裝與清理:remove、purge、autoremove 的區別
以 nginx 為例走一遍:
sudo apt-get remove nginx # 刪程式,/etc/nginx 還在
dpkg -l | grep '^rc' # 列出“已解除安裝但配置還在”的包
sudo apt-get purge nginx nginx-common # 連配置一起刪
sudo apt-get autoremove --purge # 順帶刪掉當初自動裝上、現在沒人需要的依賴
dpkg -l 第一列的 rc 表示期望狀態是刪除(r),當前只剩配置檔案(c)。一次性清掉所有殘留配置:
dpkg -l | awk '/^rc/ {print $2}' | xargs -r sudo apt-get purge -y
三點要注意:
- purge 只刪包管理器登記過的檔案,網站目錄、上傳檔案這類你自己放進去的內容不會刪。部分資料庫軟體包在 purge 時會詢問是否刪除資料目錄,看清再回答。
- autoremove 依據的是“自動安裝”標記。依賴包裝上時被標記為 auto,不再被任何包需要時就會被 autoremove 刪掉。某個依賴你想單獨留著,執行
apt-mark manual 包名改成手動安裝;apt-mark showauto能看到全部自動安裝的包。解除安裝一個元包(比如桌面環境的總包)之後,autoremove 可能列出一大串要刪的軟體,先加-s模擬再決定。 - 舊核心也靠 autoremove 清理。APT 會自動保護正在執行的核心和最新的核心不被刪除,更早的舊核心會出現在 autoremove 的列表裡。
/boot分割槽不大的機器,核心升級幾次後可能裝不下新核心,定期執行一次即可,不要手工刪/boot裡的檔案。
下載快取預設留在 /var/cache/apt/archives,用 du -sh /var/cache/apt/archives 看佔了多少,apt-get clean 全部清掉,以後需要時會重新下載。
apt-get download 與離線安裝
apt-get download 包名 把 .deb 下載到當前目錄,不需要 root,也不會安裝。單獨拿一個包時很方便,比如想看看包裡有哪些檔案:
apt-get download ipmitool
dpkg -c ipmitool_*.deb # 列出包內檔案
dpkg -x ipmitool_*.deb ./x # 解包到 ./x 目錄,不安裝
它不帶依賴,給沒有外網的伺服器準備安裝包時,要把依賴一起下載。在一台能上網、發行版版本和 CPU 架構都與目標機相同的機器上執行:
mkdir ipmitool-debs && cd ipmitool-debs
apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests \
--no-conflicts --no-breaks --no-replaces --no-enhances ipmitool | grep '^\w' | sort -u)
這樣會把整條依賴鏈都下載下來,其中不少目標機上已經裝了,安裝時同版本的包會被跳過。如果報 Can't select candidate version from package ... as it has no candidate,說明列表裡混進了虛擬包名(如 debconf-2.0),它沒有對應的 .deb,把這個名字從列表裡去掉再下載即可。把目錄拷到目標機後安裝:
sudo apt-get install ./*.deb
版本必須對應:給 Ubuntu 24.04 準備的包,就要在 24.04 上下載,混用版本是離線安裝失敗最常見的原因。機房裡要維護的機器一多,與其每次手工搬包,不如在內網放一台 apt-cacher-ng 做快取代理(預設連接埠 3142),各伺服器在 /etc/apt/apt.conf.d/ 下新建一個檔案,寫入 Acquire::http::Proxy "http://10.10.0.5:3142";,同一個包只從外網下載一次。軟體源位址是 https 的,快取需要另外配置,以 apt-cacher-ng 文件為準。
伺服器上常見的 apt-get 報錯
| 報錯 | 原因 | 處理 |
|---|---|---|
E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 1234 (unattended-upgr) |
另一個 apt 或 dpkg 程序正在執行;Ubuntu 剛開機時常是自動安全更新 | 等它結束,用 ps -fp 1234 看是什麼程序。不要刪鎖檔案,apt 自己也會提示 removing the lock file is not a solution |
E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. |
上次安裝或升級中途斷了,比如 SSH 斷線、程序被殺 | 照提示執行 sudo dpkg --configure -a,再執行 sudo apt-get install -f |
E: Unable to locate package ipmitools |
沒有 update、包名寫錯(這裡多打了一個 s),或者包所在的元件(如 Ubuntu 的 universe)沒有啟用 | apt-get update 後用 apt-cache search 關鍵詞 找正確的包名;啟用 universe:sudo add-apt-repository universe |
The following packages have unmet dependencies 和 you have held broken packages |
第三方源的包與當前系統版本不匹配,或有包被 hold | apt-cache policy 包名 看候選版本來自哪個源;apt-mark showhold 看鎖定的包 |
You might want to run 'apt --fix-broken install' to correct these. |
系統裡已經有依賴不完整的包,之後的安裝都會被攔住 | 執行 sudo apt-get install -f,看清要刪除的包再確認 |
在遠端伺服器上做大批次升級,放在 tmux 或 screen 裡執行,SSH 斷了升級也不會被打斷,這是避免出現第二行報錯最簡單的辦法。寫進指令碼時,用下面的寫法避免升級卡在互動提問上:
export DEBIAN_FRONTEND=noninteractive
apt-get update -q
apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" dist-upgrade
DEBIAN_FRONTEND=noninteractive 讓安裝指令碼不彈出配置對話方塊;--force-confdef 和 --force-confold 合起來的意思是:新包帶來的配置檔案與你改過的版本衝突時,有預設處理方式就按預設處理,否則保留你現有的配置,不會被新版本覆蓋。
升級核心後起不來:在機房裡怎麼兜底
dist-upgrade 裝上新核心,重啟後卡住或網路卡不認,是批次升級時最怕遇到的情況。這時 SSH 已經連不上,只能從帶外進去:在 Toplink DCIM 的 IPMI 遠端管理裡開啟走 BMC 通道的 VNC 控制檯,重啟時調出 GRUB 選單。Ubuntu Server 預設隱藏這個選單,UEFI 啟動的機器在啟動時按 Esc,傳統 BIOS 啟動的按住 Shift,進入 Advanced options for Ubuntu 選上一個核心啟動。進系統後先把問題核心卸掉,或用 apt-mark hold 暫緩升級,查清原因再處理。
如果系統連舊核心也進不去,租用伺服器的客戶可以在客戶自助端切到救援模式,掛載原來的系統盤,用 chroot 進入後執行 dpkg --configure -a 或重灌核心包,硬碟上的資料不受影響。批次升級前先挑一兩台做驗證,確認重啟正常再全面鋪開,比事後救火省事得多。
常見問題
apt-get 一定要用 root 執行嗎?
會改動系統的子命令(update、install、remove、upgrade、clean 等)需要 root 或 sudo。apt-get download、加 -s 的模擬執行,以及 apt-cache 的各種查詢,普通使用者就能執行。
怎麼查一個命令屬於哪個軟體包?
已經裝上的,用 dpkg -S 加命令的完整路徑,例如 dpkg -S /usr/bin/ipmitool;還沒裝的,先 apt-get install apt-file,執行 apt-file update 後用 apt-file search bin/命令名 查詢。Ubuntu 上直接輸入一個沒裝的命令,通常也會提示該裝哪個包。
/etc/apt/sources.list 裡只剩註釋,軟體源配在哪裡?
Ubuntu 24.04 起預設改用 deb822 格式,軟體源寫在 /etc/apt/sources.list.d/ubuntu.sources 裡,一個源是一段 Types、URIs、Suites、Components 欄位。換映象就改這個檔案的 URIs 行,改完執行 apt-get update。