為什麼要用 Unix 命令列工具#

除錯時經常會遇到前所未見的問題,你慣用的 IDE 可能缺乏足夠的工具來深入探索。Unix 命令列工具是通用型工具,可以透過 pipeline 組合成強大的分析流程,輕鬆處理各種文字資料。

這些文字資料包括:

  • 程式原始碼、程式日誌
  • 版本控制歷史、檔案清單
  • Symbol tables、錯誤訊息
  • 測試結果、profiling 數據

比起用 Perl、Python 等腳本語言寫一個獨立程式,直接在 shell 中組合 Unix 工具往往更快、更靈活。你可以逐步建構命令,直到得到想要的結果。

除錯 pipeline 的基本模式#

大多數除錯用的 one-liner 遵循這個模式:取得 (fetch) → 選取 (select) → 處理 (process) → 彙整 (summarize),並用 pipeline (|) 串接各步驟。

取得資料#

  • 文字檔案:直接作為標準輸入
  • object 檔案:使用 nm (Unix)、dumpbin (Windows)、javap (Java)
  • 壓縮檔:使用 tarjarar
  • 檔案系統:使用 find 搜尋
  • 網路資料:使用 curlwget
  • 編譯器錯誤:用 2>&12>filename 重導 standard error
# 找出所有 object 檔案中呼叫 exit 的模組
nm -A *.o | grep 'U exit$'

選取與過濾#

  • cut:從固定欄位或分隔符號中擷取特定欄位
  • sed:用正規表達式替換來擷取特定部分
  • grep:篩選符合條件的列;-v 過濾不要的列
  • fgrep:用 -f 旗標比對固定字串清單
# 從 system trace 輸出中取得成功開啟的檔案名稱
grep '^open(' trace.out |
grep -v '= -1' |
awk -F\" '{print $2}'

處理與彙整#

  • sort:排序(支援多種排序鍵與數值排序)
  • uniq -c:計算重複次數
  • wc -l:計算行數
  • head / tail:取最前或最後 N 筆
  • diff:比較兩次執行的結果
  • comm:比較兩個已排序的清單
  • awk:進階欄位處理與數值運算
# 找出某檔案最常修改的作者
git blame --line-porcelain Foo.java |
grep '^author ' |
sort |
uniq -c |
sort -rn |
head

用 Shell 膠水連接一切#

  • xargs:將清單傳遞為多個命令引數
  • -print0 / -0:處理含空白的檔案名稱
  • while read:迴圈處理每一行
# 找出修改 foo.cpp 後,含最多 "access failure" 的 log 檔
find /var/log/acme -type f -cnewer ~/src/acme/foo.cpp -print0 |
xargs -0 fgrep -c 'access failure' |
sort -t: -rn -k2 |
head -1

當中間處理步驟變得太複雜時,不要害怕使用暫存檔案來分段處理。

重點回顧#

  • 透過 Unix 命令組合 pipeline,可以快速完成複雜的文字資料分析
  • 基本模式為「取得 → 選取 → 處理 → 彙整」
  • grepsortuniqawkxargs 是除錯時最常用的工具
  • 善用 2>&1 重導 standard error 以便分析編譯器或程式的錯誤輸出