行命令全解析:從 help 查閱到實際排查技巧)
年初換了一臺新的開發(fā)機(jī)裝完驅(qū)動和平臺工具后我盯著黑底白字的終端窗口愣了一下明明裝了 adb卻一時想不起來它能跑哪些命令。網(wǎng)上的命令清單看過不少真到了要用的時候腦子里只?!癷nstall、shell、logcat”這幾個高頻詞。相信不少剛接觸 Android 調(diào)試的朋友也遇到過類似的情況——文檔翻了半天輪到自己敲命令就卡殼。這篇內(nèi)容就從“查看 adb 可執(zhí)行命令”這個最基礎(chǔ)的動作講起把 adb 命令體系的查閱邏輯、常見誤區(qū)和實際排查技巧一次性說透讓新手少走彎路也讓老手能回頭補(bǔ)上幾個平時沒注意過的細(xì)節(jié)。1. 先弄清楚 adb 命令體系的基本構(gòu)成1.1 adb 不是單個工具而是一套三層結(jié)構(gòu)很多初學(xué)者容易有個誤區(qū)以為 adb 是安裝在手機(jī)上的某個應(yīng)用或者以為 adb 就是手機(jī)上那個調(diào)試開關(guān)。其實 adbAndroid Debug BridgeAndroid 調(diào)試橋由三部分組成運行在電腦上的客戶端、電腦后臺常駐的服務(wù)端以及運行在 Android 設(shè)備上的守護(hù)進(jìn)程adbd。平時你在終端里敲下的每一個 adb 命令本質(zhì)上是客戶端把請求發(fā)給電腦上的服務(wù)端服務(wù)端再通過 USB 或 TCP 與設(shè)備里的 adbd 通信。這個架構(gòu)帶來的一個重要結(jié)果是adb 命令能不能執(zhí)行、能執(zhí)行哪些并不完全由你手上的這個 adb 版本決定還取決于設(shè)備端 adbd 的能力和當(dāng)前連接狀態(tài)。比如adb install和adb shell這類命令既要客戶端支持也要設(shè)備端 adbd 配合。如果設(shè)備處于 unauthorized 狀態(tài)未授權(quán)調(diào)試絕大多數(shù)命令會直接報錯如果設(shè)備處于 offline 狀態(tài)命令則會一直卡住直到超時。理解了這個三層結(jié)構(gòu)后面再看命令幫助時你就能自然地把命令分成“本地就能跑”和“必須依賴設(shè)備”兩大類排查問題時也會更有方向感。1.2 “可執(zhí)行命令”到底指什么當(dāng)我們說“查看 adb 可執(zhí)行命令”時其實包含兩層含義當(dāng)前 adb 版本支持的命令全集例如adb install、adb pull、adb push、adb reverse、adb forward等。在當(dāng)前環(huán)境連接的設(shè)備、網(wǎng)絡(luò)狀態(tài)、系統(tǒng)權(quán)限下實際能跑通的命令子集。第一層信息靠adb help或adb --help就能拿到任何機(jī)器上都一樣第二層則需要結(jié)合設(shè)備狀態(tài)、授權(quán)情況、系統(tǒng)構(gòu)架來判斷。一個很典型的例子是adb reboot bootloader在大多數(shù)手機(jī)上可以執(zhí)行但如果設(shè)備是某廠商定制系統(tǒng)或者已經(jīng)處于 fastboot 模式那命令的返回結(jié)果和后續(xù)表現(xiàn)就跟默認(rèn)情況不太一樣。所以查閱“可執(zhí)行命令”不只是一個 help 輸出那么簡單它背后牽涉到命令分類、參數(shù)理解、協(xié)議對接甚至精確到版本差異。下面我按實際使用場景把查閱和排查的完整鏈路拆開來講。2. 用 adb help 快速梳理命令全貌2.1 help 輸出的四個區(qū)塊在終端里輸入adb help或者adb --help兩者等價你會看到一屏以Android Debug Bridge version x.x.x開頭的輸出。以我長期使用的經(jīng)驗來看這段輸出大致可以分成四塊全局參數(shù)區(qū)位于開頭以-d、-e、-s、-H、-P、-L等全局選項為主。它們決定 adb 連接哪臺設(shè)備、走什么傳輸通道往往要寫在具體命令之前。通用命令區(qū)也就是devices、help、version、start-server、kill-server這些不依賴特定推送、安裝場景的基礎(chǔ)命令。設(shè)備與調(diào)試區(qū)包括install、uninstall、pull、push、shell、logcat、forward、reverse、pair、mdns等是所有開發(fā)者日常打交道最頻繁的區(qū)域。服務(wù)與網(wǎng)絡(luò)區(qū)涉及連接無線調(diào)試、同步文件、重啟服務(wù)等邏輯例如connect、disconnect、sync、emu、reboot等。不同版本的 adb 在這一屏上的行數(shù)會有出入。比如我早年用的某版本adb help輸出末尾還會出現(xiàn)一個internal debugging commands區(qū)塊里面列的是非公開的調(diào)試入口而新版本里這些內(nèi)容有的被移到文檔之外有的干脆被刪掉了。所以看到 help 輸出跟網(wǎng)上教程截圖的順序不一致不用太驚訝這不是你的問題是版本演進(jìn)帶來的正常差異。2.2 全局選項為什么必須提前看很多教程會跳過adb help開頭的全局選項直接講具體命令但我想專門提醒一句全局選項決定了“命令作用到誰身上”。舉個例子-s 序列號可以指定某臺設(shè)備-d指定唯一連接的 USB 設(shè)備-e指定唯一連接的模擬器。當(dāng)電腦上同時連著真機(jī)和模擬器或者連著兩臺真機(jī)時不帶這些選項直接敲adb install極大概率會報more than one device/emulator錯誤。而-H和-P則是連接遠(yuǎn)程 adb 服務(wù)端的參數(shù)在辦公環(huán)境里通過內(nèi)網(wǎng)調(diào)試盒子時非常有用但是多數(shù)人平時接觸不到。-L這個參數(shù)稍微特殊一點它可以直接指定一個完整的 socket 地址。比如你想讓 adb 客戶端連接某個自定義監(jiān)聽端口就可以寫成adb -L tcp:6555 connect 192.168.1.10:6555這類用法。我當(dāng)年第一次看到-L是在排查一臺 USB 識別時好時壞的開發(fā)板時當(dāng)時就是用-L繞過默認(rèn)端口直連另一臺宿主機(jī)上的 adb server才把問題定位到本地 USB 枚舉環(huán)節(jié)。所以翻 help 時不要只盯著命令列表全局參數(shù)區(qū)才是你在多設(shè)備、特殊網(wǎng)絡(luò)環(huán)境下“保命”的法寶。建議第一次看adb help時把全局參數(shù)區(qū)逐條過一遍至少做到眼熟。2.3 怎么看懂 help 輸出里的參數(shù)標(biāo)記adb help里每個命令后面會跟著類似[-r] [-s] [-d]這樣的標(biāo)記初次接觸容易懵。其實規(guī)則很簡單方括號[]表示可選參數(shù)尖括號表示必須由你填寫的占位符比如adb install package.apk豎線|表示多選一比如-d|--device是同一個功能的兩種寫法有些參數(shù)后面還會有一行小字說明用途例如-r表示替換已安裝應(yīng)用-t表示允許安裝測試包。adb help的輸出命名習(xí)慣在不同版本上也略有差異老版本喜歡用adb install [-lrtsdg]這種緊湊寫法新版本則會把每個參數(shù)獨立成行并附上解釋。如果是新版本閱讀體驗會好很多如果是老版本建議對照網(wǎng)上資料或直接adb help install看子命令詳解。我自己維護(hù)的一臺測試機(jī)上至今還是某舊版平臺工具它的adb help輸出簡略到令人懷疑人生但它仍然能正常跑大部分命令。教訓(xùn)就是幫助信息詳略不代表功能強(qiáng)弱一切以實際執(zhí)行為準(zhǔn)。3. 深入子命令幫助從“知道有哪些”到“知道怎么用”3.1 adb help 后面還能跟子命令很多人不知道adb help還能繼續(xù)接子命令例如adb help install、adb help shell、adb help logcat。這是我在本地把 adb 命令文檔吃透的最快途徑也是解決“命令存在但參數(shù)記不清”這類問題的標(biāo)準(zhǔn)動作。以adb help shell為例它輸出的不是 shell 的使用說明而是告訴你adb shell本身支持哪些參數(shù)比如-t分配偽終端、-n不分配偽終端、-e指定 escape 字符以及遠(yuǎn)程命令應(yīng)該如何傳參。在 Android 9 之前adb shell后面直接跟命令即可在 Android 10 及以上版本中部分交互式指令對偽終端分配變得敏感-t或缺省分配策略的影響會被放大。如果你用adb shell執(zhí)行腳本時遇到輸出重定向異常先查一下這個子幫助多半能找到答案。同樣地adb help install會展開很多安裝細(xì)節(jié)參數(shù)例如-g授予所有運行時權(quán)限、-i指定包名、-S使用流式安裝、--abi指定 CPU 架構(gòu)等。這些參數(shù)在初級教程里很少被展開但實際工程中非常實用。比如你要在一臺 x86 模擬器上強(qiáng)制安裝 arm 架構(gòu)的測試包--abi參數(shù)就派得上用場。3.2 子命令參數(shù)的最佳查閱方式命令本身加 -h除了adb help 子命令還有另一套查閱路徑是直接在子命令后加-h或--help比如adb install --help、adb push --help。兩個寫法在大多數(shù)版本里效果等同但個別老版本對-h的處理不一致可能會把-h當(dāng)作某個子命令的業(yè)務(wù)參數(shù)比如安裝時的-h在部分版本不會被識別為 help。為了穩(wěn)妥起見我個人的習(xí)慣是優(yōu)先用adb help 命令如果這條命令恰好不在主幫助列表里再退回adb 命令 --help試一次。需要注意的是adb shell之后的命令例如adb shell am ...、adb shell pm ...、adb shell dumpsys ...走的是另一套邏輯。這些命令由設(shè)備端的 shell 解析--help是否可用完全取決于設(shè)備上對應(yīng)工具的實現(xiàn)。比如dumpsys --help在絕大多數(shù)設(shè)備上能彈出一大屏參數(shù)但am --help在某些深度定制的系統(tǒng)里可能只返回簡單的 usage 甚至直接報錯。遇到這種情況不是你的 adb 有問題而是設(shè)備端工具版本不一致。排查時可以先adb shell進(jìn)到設(shè)備端再用which am、cmd --help等方式確認(rèn)工具是否存在。3.3 分組記憶把 adb 命令拆成五類命令多了不好記我習(xí)慣把它們拆成五個互相獨立的類別。這樣做的好處是當(dāng)你忘了某個具體命令時可以快速從類別定位再用 help 縮小范圍。連接管理類devices、connect、disconnect、pair、mdns負(fù)責(zé)建立、維護(hù)、斷開設(shè)備連接。應(yīng)用管理類install、uninstall、cmd package、am force-stop處理安裝、卸載、啟停和權(quán)限操作。文件與端口類push、pull、sync、forward、reverse在電腦與設(shè)備之間搬運數(shù)據(jù)、建立端口映射。日志與調(diào)試類logcat、shell、bugreport、dumpsys、screenrecord負(fù)責(zé)取證、調(diào)試和性能分析。系統(tǒng)控制類reboot、shutdown、root、unroot、remount、sideload管理系統(tǒng)的重啟、權(quán)限與分區(qū)狀態(tài)。這個分組不是官方標(biāo)準(zhǔn)但幫我省了不少記憶成本。比方說我想清理應(yīng)用緩存按分類會先跳到“應(yīng)用管理類”然后想到adb shell pm再想到pm clear 包名。如果暫時記不清參數(shù)adb help shell或adb shell pm --help都能快速補(bǔ)上。4. 開發(fā)機(jī)上幾個容易忽略的“查命令”技巧4.1 Tab 鍵自動補(bǔ)全最省事的命令探索器主流 shellbash、zsh、fish都支持命令補(bǔ)全但很多人只在文件名上使用補(bǔ)全忽略了 adb 子命令也能補(bǔ)全。只要你的 shell 補(bǔ)全規(guī)則沒被額外禁用輸入adb inst后按 Tab 鍵bash 會自動補(bǔ)全為adb install輸入adb sh再按 Tab則可能直接補(bǔ)全為adb shell。遇到多個匹配項時連續(xù)按兩次 Tab 會列出候選列表比如輸入adb re后按兩下 Tab會看到reboot、reverse、remount等候選命令。這背后的機(jī)制是發(fā)行版自帶的bash-completion包或 zsh 的compinit在配合 adb 的二進(jìn)制可執(zhí)行文件做參數(shù)解析。某些精簡系統(tǒng)上可能沒裝 bash-completion這時 Tab 補(bǔ)全只對路徑生效對子命令不生效。解決辦法很簡單sudo apt install bash-completionDebian/Ubuntu 系或brew install bash-completionmacOS 系安裝補(bǔ)全增強(qiáng)然后在.bashrc里啟用。對日常頻繁敲 adb 的人來說這一步能把輸入錯誤率降低一大截。zsh 用戶還有額外的福利可以安裝一個adb補(bǔ)全插件它會基于當(dāng)前設(shè)備狀態(tài)動態(tài)補(bǔ)全包名、序列號、日志 tag 等參數(shù)。這個高級能力不改變 adb 本身但能讓“查看可用命令”從靜態(tài)幫助變成動態(tài)提示明顯提升效率。4.2 使用 alias 和函數(shù)把常用檢查命令固化成快捷指令“查看 adb 可執(zhí)行命令”這件事本身也可以被固化。我在自己的.bashrc里長期保留了這樣幾行alias adbsadb devices -l alias adbhadb help alias adbhladb help | lessadb devices -l會輸出比普通adb devices更豐富的設(shè)備信息包括型號、傳輸方式、序列號。用它來確認(rèn)電腦是否發(fā)現(xiàn)設(shè)備是我每次連接新手機(jī)之后的第一動作。adb help | less則是把 help 輸出送進(jìn)分頁器解決一屏刷不完的問題。如果你經(jīng)常要在不同機(jī)器之間同步 adb 環(huán)境還可以寫一個小腳本在 shell 初始化時自動執(zhí)行adb version和adb devices把當(dāng)前環(huán)境狀態(tài)直接打印出來。這樣每次打開終端第一眼就知道 adb 版本和連接狀態(tài)不用再手動確認(rèn)。4.3 保持平臺工具版本最新避免命令缺失adb help列出的命令集在不同版本之間確實有差異這不是錯覺。某些命令可能只在特定版本之后才出現(xiàn)例如無線調(diào)試相關(guān)的adb pair和adb mdns在舊版平臺工具里是沒有的。如果你照著新教程敲adb pair卻提示未知命令先檢查版本adb version以我的經(jīng)驗跟蹤最新平臺工具版本很有必要。Google 官方的 Android 開發(fā)者網(wǎng)站有平臺工具下載頁不同操作系統(tǒng)的安裝包都有對于部分 Linux 發(fā)行版軟件源里的 adb 版本可能滯后需要手動下載官方二進(jìn)制覆蓋。版本也不是越新越好如果手頭有舊的嵌入式設(shè)備或定制 ROM新版本 adb 反而可能因為協(xié)議變化連不上老設(shè)備。最穩(wěn)妥的做法是主環(huán)境用官方新版本同時保留一個舊版平臺的獨立目錄需要時直接指定絕對路徑調(diào)用。4.4 環(huán)境變量和 adb_SERVER_SOCKET 對命令可見性的影響“可執(zhí)行命令”有時不是不夠而是被環(huán)境變量限制了。ADB_SERVER_SOCKET和ANDROID_SERIAL是兩個常見的坑。ADB_SERVER_SOCKET默認(rèn)指向tcp:5037如果被改成別的地址adb 客戶端會嘗試連接那個地址上的服務(wù)端。服務(wù)端版本不一致時你敲出的命令可能返回莫名錯誤甚至某些高層命令直接被拒絕。排查套路是env | grep -i adb看到ADB_SERVER_SOCKET被設(shè)置而你又不需要遠(yuǎn)程調(diào)試時直接unset ADB_SERVER_SOCKET即可恢復(fù)默認(rèn)行為。ANDROID_SERIAL則會影響所有不帶-s參數(shù)的 adb 命令。假設(shè)你設(shè)置了它指向某臺模擬器那么adb devices雖然會列出真機(jī)但adb install這類命令仍然只對模擬器執(zhí)行。這類“命令在但沒跑對設(shè)備”的問題比“命令缺失”更難察覺因為報錯信息通常會和設(shè)備序列號相關(guān)容易被誤讀成硬件故障。優(yōu)先檢查環(huán)境變量往往能省下十分鐘的排查時間。5. 命令明明存在卻執(zhí)行失敗先按這個思路排查5.1 設(shè)備狀態(tài)先于命令語義判斷當(dāng)adb install、adb shell或adb pull執(zhí)行報錯時我一般不看命令語法先確認(rèn)設(shè)備狀態(tài)adb devices -l輸出中設(shè)備狀態(tài)有三種常見形態(tài)device、offline、unauthorized另外還有可能看到no permissions。它們對應(yīng)的含義和處置方式差別很大狀態(tài)含義常見原因通常處置device正常連接已授權(quán)無直接執(zhí)行命令offline設(shè)備在線但通信異常USB 線纜劣質(zhì)、驅(qū)動沖突、服務(wù)端緩存重插 USBadb kill-server后重啟服務(wù)unauthorized設(shè)備未確認(rèn)調(diào)試授權(quán)手機(jī)彈窗未點允許、密鑰變更在手機(jī)上重新授權(quán)no permissions系統(tǒng)層面禁止訪問 USBudev 規(guī)則缺失配置 udev 規(guī)則并重載很多“命令找得到但執(zhí)行不了”的問題根子都在這里而不是命令本身寫錯。尤其no permissions狀態(tài)最常出現(xiàn)在 Linux 系統(tǒng)上因為當(dāng)前用戶不在plugdev用戶組或缺少對應(yīng)的 udev 規(guī)則。這時候用adb devices能看到設(shè)備但一執(zhí)行adb shell就提示no permissions。排查辦法是查看/etc/udev/rules.d/下是否有相關(guān)規(guī)則并把當(dāng)前用戶加入plugdev組然后udevadm control --reload-rules udevadm trigger。5.2 命令存在但報未知命令檢查 shell 內(nèi)部指令另一種情況更迷惑adb help里明明列出了某個命令但在設(shè)備端執(zhí)行時卻提示command not found。這通常發(fā)生在adb shell之后例如adb shell avbctl --help如果設(shè)備沒有avbctl部分系統(tǒng)才有就會報找不到。這不是 adb 的問題而是設(shè)備端 Android 系統(tǒng)里壓根沒有這個工具。同理在不同 Android 版本和定制系統(tǒng)里dumpsys、cmd、service這些命令的存在性也不完全一致。處理辦法是先用adb shell ls /system/bin或者adb shell which 命令名確認(rèn)設(shè)備端是否有對應(yīng)二進(jìn)制盲目安裝“萬能命令”只會把問題搞得更亂。還有一類常見于廠商定制系統(tǒng)adb shell am force-stop明明能執(zhí)行但返回一個偽裝的 success實際上沒有殺掉目標(biāo)進(jìn)程。這種“假成功”不屬于命令層面而是廠商改了權(quán)限或調(diào)度策略。遇到這種情況可以交叉驗證adb shell ps -A | grep 包名再看進(jìn)程是否還在。如果還在說明命令沒真正生效需要換adb shell am kill或pm clear配合使用。5.3 服務(wù)端卡死導(dǎo)致命令集體失效除設(shè)備狀態(tài)外本地 adb server 的“卡死”也是一個高頻坑。癥狀是adb devices正常但任何具體命令都卡住或返回cannot connect to daemon。我遇到過幾次之后總結(jié)出一個規(guī)律多半是宿主機(jī)某進(jìn)程占用了 5037 端口或者舊服務(wù)端與新客戶端版本不匹配。排查方式adb kill-server adb start-server adb devices如果kill-server本身也卡住可以直接查端口占用lsof -i:5037看到不是 adb 的進(jìn)程占用時先處理那個進(jìn)程再重啟 adb server。這套操作基本能解決 90% 的“命令集體失效”問題。另外提醒一點不要在服務(wù)端運行期間隨意拷貝其他版本的 adb 二進(jìn)制替換當(dāng)前文件這會導(dǎo)致客戶端和服務(wù)端協(xié)議握手上出現(xiàn)隱蔽故障表現(xiàn)出來可能是某些命令正常、某些命令異常非常難查。5.4 無線調(diào)試場景下的命令列表差異Android 11 之后無線調(diào)試逐漸普及adb pair和adb mdns services這類命令的使用場景越來越多。無線調(diào)試環(huán)境下adb devices -l輸出里的傳輸方式字段會變成wireless且序列號是IP:端口格式。很多人第一次看到這個格式會誤以為是命令識別異常其實這是正常的。無線連接狀態(tài)下“可執(zhí)行命令”全集本身沒有變化但執(zhí)行體驗差異很大。比如adb reboot后無線連接會斷開adb root在部分系統(tǒng)上也會觸發(fā)連接重置adb shell ifconfig這類命令在僅開無線調(diào)試、關(guān)閉 USB 調(diào)試的某些設(shè)備上照樣能執(zhí)行因為 adbd 不受 USB 通道限制。需要專門留意的反而是 TCP 端口換網(wǎng)絡(luò)環(huán)境后原本的IP:端口可能失效需要重新adb pair。這時候再看adb help重點就會落到pair和connect參數(shù)的用法上也算是對“查看可執(zhí)行命令”的一種動態(tài)理解。6. 從命令清單到實際工程效率6.1 建立一份你自己的 adb 速查表adb help的輸出畢竟是通用參考不能完全反映你的項目需求。經(jīng)過一段時間摸索后我建議每個人都維護(hù)一份自己的速查表。格式不必復(fù)雜可以用普通的 Markdown 表格按項目階段羅列出高頻命令。比如我的個人表里會有如下條目使用場景命令用途說明連接確認(rèn)adb devices -l查看設(shè)備、狀態(tài)、傳輸方式安裝測試包adb install -r -t 包路徑允許更新和測試包查看日志adb logcat -v time *:E只看錯誤級別及時間信息截取屏幕adb exec-out screencap -p 本地.png比adb shell screencap更快落地臨時端口映射adb reverse tcp:8081 tcp:8080手機(jī)訪問電腦本地服務(wù)重啟到 bootloaderadb reboot bootloader進(jìn)入底層刷機(jī)模式真正記錄下來的命令才是屬于你自己的“可執(zhí)行命令清單”因為它貼合你的項目、設(shè)備和調(diào)試習(xí)慣比任何人給你一份大而全的命令列表都實用。6.2 結(jié)合快速反饋把 help 變成肌肉記憶最后想說一個方法論層面的體會查看命令幫助這件事最忌諱“一次性看完”。就像背單詞一樣看一遍記不住真正常用。我在新環(huán)境里第一次跑通一個 adb 流程會順手adb help對照一次遇到新報錯也會先adb help定位命令歸類再單獨查子命令幫助。這個過程本質(zhì)上是把靜態(tài)清單通過反饋循環(huán)變成肌肉記憶。時間久了你會發(fā)現(xiàn)腦子里的 adb 命令地圖越來越清晰哪個命令屬于哪一類、哪些參數(shù)是“保命”級別、哪些參數(shù)只在特定版本里存在都一清二楚。到了這一步你再也不怕別人突然問你“adb 能執(zhí)行哪些命令”因為你關(guān)心的早已不是那屏輸出而是你自己項目里的那一組常用可執(zhí)行子集。說實話查 adb 命令這件事屬于典型的“會者不難難者不會”。掌握了基本查閱邏輯和排查順序后續(xù)的調(diào)試效率會有非常明顯的提升。希望這篇整理能幫你省下翻文檔的時間。