1. 程式人生 > >Linux -高階命令行技巧

Linux -高階命令行技巧

ace 一個 顯卡 apt slurm pid 令行 gen 意見

熟練地操作命令行是一項常常被我們忽視的技能,又或者說我們將它看的太過神秘。不過作為一名軟件工程師,掌握這一技能可以很大程度上提升我們工作的靈活性,提高工作效率。這篇文章是我在與 Linux 打交道的過程中總結出的一些小技巧。有些很基礎,有些也相當專業,不太好懂。這篇文章不長,不過如果你能在工作中充分使用這裏介紹的技能的話,那你也知之甚多了。

這裏的許多內容一開始已出現在 Quora,但考慮到 Github 的用戶性質,他們比我有天賦而且可以隨時提出改進意見,因此使用 Github 更合適。如果你在本文中發現了錯誤或者存在可以改進的地方,請果斷提交 Issue 或 Pull Request!(當然在提交前請看一下必讀節和已有的 PR/issue)。

必讀

  • 這篇文檔對新手與專家兩相宜。我們的目標是覆蓋面廣(盡量包括一切重要的內容),具體(給出最常見的具體的例子)以及簡潔(避免一些不必要以及不相幹的東西)。 這裏介紹的小技巧可能在某個特定情境下至關重要,又或者能夠顯著地節約時間。

  • 本文為 Linux 所寫,除了“僅限 MacOS 系統”一節。其它節中的大部分內容都適用於其它 Unix 系統或 MacOS 系統,甚至 Cygwin。

  • 雖然我們介紹大多數技巧對其他 shell 以及 Bash 腳本同樣管用,但是本文的關註點是:交互式 Bash。

  • 這裏涵蓋了“標準” Unix 命令以及其他需要安裝指定軟件包的命令——只要這個命令足夠重要,足夠管用,我就會在這裏提一提。

編註:為了控制篇幅,有些內容包含在引用裏面。你也可以通過 google 之類的工具來搜索詳細信息。使用 apt-get/yum/dnf/pacman/pip/brew 等命令來安裝新程序。

使用 Explainshell 來獲取命令、選項、管道等相關信息的幫助。

基礎

學習基礎的bash用法,具體地說,閱讀bash的man手冊(man bash 並通讀一遍);很簡單而且不長。其他的shell也同樣可以,不過bash 是最通用的(如果只學習 zsh, fish 等,可能在你自己的工作環境中會用的很順暢,但是換個場景就歇菜了,比如在服務器上操作)。

至少學習一種文本編輯器。最好是 vim (vi), 在終端隨機編輯文檔方面,其他編輯器跟它相比沒有一點競爭力(即使大部分時間你用的是其他一些大型 IDE,比如 Emacs,或者一些其他時髦的編輯器)。

知道怎樣通過 man 來閱讀文檔(好奇心重的人可能就直接 man man了,列出不同章節號,如:1表示普通的shell命令, 5表示文件格式和規範, 8 代表系統管理命令等)。學會使用 apropos 來查找 man 手冊。要知道有些命令不是可執行文件,而是 bash 內置的,對於這種命令呢,可以使用 help 或者 help -d 來獲取幫助(例如 cd)。

學會使用 > 和 < 來重定向輸入輸出,學會使用 | 來建立管道。了解 > 用於覆蓋輸出文件, >> 用戶追加到輸出文件。 學習標準輸出 stdout 和 標準錯誤 stderr。

學習文件通配符 * (可能還有 ? 和 {…})和引用,明白雙引號和單引號的區別。(詳細信息看下面的變量展開)

熟練掌握 bash 的任務管理器: &、ctrl-z、ctrl-c、jobs、fg、bg、kill 等等。

熟悉 ssh, 並且知道如何通過 ssh-agent, ssh-add等實現無密碼認證。

基本的文件管理命令: ls 和 ls -l (特別地, 你得知道ls -l 結果中的每一列是什麽意思),less, head, tail 和 tail -f(最好也弄清楚 less +F 是嘛意思), ln 和 ln -s (了解硬鏈接和軟連接的區別和優缺點), chown, chmod, du (磁盤使用情況: du -hk *)。對文件系統來說, df, mount, fdisk, mkfs,lsblk。

基本的網絡管理命令: ip 或者 ifconfig, dig。

熟練掌握正則表達式,以及grep/egrep 工具的多種標誌。有必要知道 -i, -o, -A 以及 -B 選項的意思。

學會使用 apt-get, dnf 或者 pacman(根據不同的發行版選擇)來查找或者安裝軟件包。確保你安裝了 pip 來安裝 python 相關的命令行工具。(下面介紹的那些工具都可以使用 pip 來安裝)

日常使用

在 Bash中,使用 Tab 鍵來補全命令,使用 ctrl-r 來查詢歷史命令。

在 Bash 中,使用 ctrl-w 來刪除上一個單詞,ctrl-u 刪除整行命令。使用 alt-b 和 alt-f 來逐單詞向前向後跳轉,ctrl-k 將鼠標位置到行末的所有字符刪除,ctrl-l清屏。查看 man readline 中的”Key Bindings”這一節了解 Bash 中默認的組合鍵。還有其他的很多,比如說 alt-. 可以用來上翻之前的命令,alt-* 擴展為當前目錄下的所有文件。

如果你偏好 vi風格的組合鍵,可以 set -o vi。

使用history命令查看近期的命令。還有其他許多簡寫命令,比如 !$表示上一個參數,!!執行上一條命令等。不過通常我們更常用的是 ctrl-r和alt-. 。

回到上一個工作目錄: cd –

如果你命令敲到一半發現還有其他事沒做,想要稍後執行,怎麽辦呢?使用 alt-# 給這條命令行首加上#,再回車當做一條註釋(或者使用 ctrl-a,#,回車)。之後通過歷史命令找它回來繼續往下敲。

Xargs 或者 parallel 命令也很管用。我們還可以使用 -L 或者 -P 選項限制每行參數個數。如果對執行結果不確定的話,可以先用 xargs echo 查看。同樣, -I{} 選項用起來也很順手。例如:

find . -name ‘*.py‘ | xargs grep some_function

cat hosts | xargs -I{} ssh root@{} hostname

【補充 : find . -name “.dsc” | xargs -L 2 echo 可以將當前目錄下所有 .dsc 文件列出,並且限制每行顯示兩項。

find . -name “.dsc” | xargs -I{} mv {} {}.bak 可以將當前目錄下所有後綴為 .dsc 的文件更名為 .dsc.bak

-I 選項告知 xargs 用每項的名稱替換 {}】

Pstree -p 可以很清晰的展示進程樹。

使用 pgrep 和 pkill 來根據名稱找出進程或者向進程發送信號 (註意 -f 的用法)

了解一些發送給進程的信號。比如,可以使用 kill -STOP [pid] 來停止進程。 Man 7 signal 查看全部列表。

使用 nohup 或者 disown 命令讓程序在後臺一直運行。

通過 netstat -lntp 或者 ss -plat 命令來檢查哪些進程正在監聽端口(默認情況下監聽 TCP 端口, 使用 -u 監聽 UDP)。

使用 lsof 查看所有打開的套接字和文件。詳情自 man

使用 alias 給常用命令創建別名。例如 alias ll=’ls -latr’ 為我們創建新的別名 ll。

在 Bash 腳本中,使用 set -x 來調試輸出。盡可能的使用嚴格模式。如果希望阻止我們的程序發生錯誤的情況下還繼續運行,可以通過設置 set -e 來限制。還可以使用 set -o pipefail 來嚴格限制錯誤(話說這種問題比較微妙,需要多領悟)。對於比較復雜而牽扯甚多的腳本,可以使用 trap 。

在 Bash 腳本中,子 shell (用括號包含)可以用來很方便的組織命令。一個常見用法是臨時切換到不同的工作目錄,例如:

# 在當前目錄工作

(cd /some/other/dir && other-command)

# 繼續在原目錄工作

請註意,在 Bash 中有多種變量展開的方式。

檢查某變量是否存在: ${name:?error message}。例如:如果某個 Bash 腳本需要一個參數, input_file=${1:?usage: $0 input_file} 就可以。

數學展開式: i=$(((i+1)%5))

序列: {1..10}

截斷字符串: ${var%suffix} 和 ${var#prefix},例如 var=foo.pdf, 命令 echo ${var%.pdf}.txt 打印 foo.txt。

通過 <(some command) 這種方式可以將命令的輸出視為文件。例如,比較本地和遠程的 /etc/hosts 文件:

diff /etc/hosts <(ssh somehost cat /etc/hosts)

要知道 Bash 中 “here documents” 的用法,比如 cat <<EOF …【man bash,搜索 Here Documents】

在 Bash 中,通過 : some-command > logfile 2>&1 的方式來重定向標準輸出和標準錯誤。通常的,為了保證你執行的命令不會在標準輸入中殘留一個打開的文件句柄,導致無法操作終端,最佳實踐是加上 </dev/null.

使用 man ascii 查看十六進制和十進制值的ASCII表。man unicode,man utf-8,以及 man latin1 有助於你去了解通用的編碼信息。

使用 screen 或者 tmux 命令來操作多屏,尤其是在連接遠程 session 、斷開或者重連 session 等情況下非常實用。另一個輕量級的保存會話的工具是 dtach。

ssh 中,了解如何使用 -L 或 -D(偶爾需要用 -R)去開啟隧道是非常有用的,例如當你需要從一臺遠程服務器上訪問 web。

優化 ssh 配置有時候可能很管用,例如下面這個 ~/.ssh/config 修改了一些配置,相對於使用默認配置的其他服務器來說,它可以有效避免特定網絡環境下連接被丟棄,使用壓縮數據(有效用於低帶寬連接中的 scp 操作),以及多通道等:

TCPKeepAlive=yes

ServerAliveInterval=15

ServerAliveCountMax=6

Compression=yes

ControlMaster auto

ControlPath /tmp/%r@%h:%p

ControlPersist yes

SSH 還有其他一些安全相關的選項,須小心使用,例如在單個子網、主機或者可信任的網絡中:

StrictHostKeyChecking=no,ForwardAgent=yes

獲取文件的八進制格式的權限,這種權限在系統配置中很管用,但是 ls 並不顯示,並且很容易搞砸。可以使用這條命令:

stat -c ‘%A %a %n‘ /etc/timezone

從另外一條命令中,以交互的方式選擇值,可以使用 percol 或者 fzf。

使用 fpp 來與其他命令輸出的文件交互(如git)【facebook PathPicker, github 上的項目,例如 git status | fpp, find . -name “*.vala” | fpp】

對一個簡單的 web 服務器來說,將當前目錄下所有的目錄(包括子目錄)展示給所處網絡的所有用戶,使用: python -m SimpleHTTPServer 7777 (使用端口 7777 和 Python 2)或python -m http.server 7777 (使用端口 7777 和 Python 3)。

以某種權限來執行命令,使用sudo(root 權限)或sudo -u(其他用戶)。使用su或者sudo bash來啟動一個指定用戶權限運行的 shell。使用su -模擬其他用戶的登錄。

文件和數據處理

在當前目錄下找到某名稱的文件, find . -iname ‘*something’ (或其他類似方式)。找到其他任意位置的某個文件,使用 locate something (但請註意: updatedb 可能無法索引到新增的文件)

在源代碼或數據文件中搜索,使用 ag(比 grep -r 更好)。

將 HTML 文件轉化為文本格式: lynx -dump -stdin

可以試試 pandoc 來對 Markdown、HTML 以及其他各種文件進行格式轉換。

如果某些情況下你需要處理 XML 數據,那麽試試 xmlstarlet 吧,雖然它有點歷史滄桑感但的確挺好用的。

對 JSON 數據來說, 用 jq。

對於 Excel 或者 CSV 文件, csvkit 提供諸如 in2csv, csvcut, csvjoin, csvgrep 等實用小工具。

關於 Amazon S3, s3cmd 很方便而 s4cmd 更快。 Amazon 官方的 aws 工具是其他 AWS 相關工作的基石。

了解如何使用 sort 和 uniq,包括 uniq 的 -u 參數和 -d 參數,詳見後文“一行命令”節。另外可以了解一下 comm。

了解如何使用 cut,paste 和 join 來更改文件。很多人都會使用 cut,但幾乎都不會使用 join。

了解如何運用 wc 去計算新行數(-l),字符數(-m),單詞數(-w)以及字節數(-c)。

知道用 tee 來將標準輸入的內容復制到文件或者標準輸出,就像 ls -al | tee file.txt

要知道語言環境可能對許多命令行工具產生微妙地影響,包括排序的順序和性能。大多數 Linux 的安裝過程會將 LANG 或其他有關的變量設置本地化。但是請註意當你改變語言環境後,排序的結果可能會隨之變化。而且國際化可能會大大降低 sort 或其他命令的運行效率。某些情況下(例如集合運算、去重操作等)你可以放心的使用 export LC_ALL=C 來忽略掉國際化並使用基於字節的順序。

了解 awk 和 sed 關於數據的簡單處理的用法。例如,將文本文件中第三列的所有數字求和:

awk ‘{ x += $3 } END { print x }‘

這可比 Python 實現的代碼量少三倍也快三倍。

perl -pi.bak -e &#039;s/old-string/new-string/g&#039; my-files-*.txt

替換一個或多個文件中出現的字符串:

perl -pi.bak -e &#039;s/old-string/new-string/g&#039; my-files-*.txt

使用 rename 完成批量文件的重命名。對於更復雜的情況,可以使用 repren[https://github.com/jlevy/repren]

# 將備份文件 foo.bak 還原至 foo

renames/.bak$//’ *.bak

# 將所有的文件名、目錄、內容等全部重命名

repren --full --preserve-case --from foo --to bar .

使用 shuf 從一個文件中隨機選取行。

了解 sort 的參數。處理數字方面,使用 -n 或者 -h 來處理可讀性數字(例如 du -h 的輸出)。明白關鍵字的工作原理(-t 和 -k)。請註意!如果你想要僅按第一個域來排序需要 -k1,1 ; -k1 意味著按整行排序。穩定排序(sort -s)在某些情況下很有用。例如,以第二個域為主關鍵字,第一個域為次關鍵字進行排序,你可以使用 sort -k1,1 | sort -s -k2,2。

如果你想在 Bash 命令行中寫 tab 制表符(舉個栗子: sort 的 -t 參數指定分隔符:sort -t”tab ” -k2 sortfile),按下 ctrl-v [Tab] 或鍵入 $’t’ (後者可能更好,因為你可以復制粘貼它)。

標準的源代碼對比及合並工具是 diff 和 patch。使用 diffstat 查看變更總覽數據。註意到 diff -r 對整個文件夾有效。使用 diff -r tree1 tree2 | diffstat 查看變更總覽數據。

對於二進制文件,使用 hd 使其以十六進制顯示以及使用 bvi 來編輯二進制。

同樣對於二進制文件,使用 strings(加上 grep 等等)允許你查找一些文本。

二進制文件對比(Delta 壓縮),使用 xdelta3。

使用 iconv 更改文本編碼。而更高級的用法,可以使用 uconv,它支持一些高級的 Unicode 功能。例如,這條命令將所有元音字母轉為小寫並移除了:

uconv -f utf-8 -t utf-8 -x ‘::Any-Lower; ::Any-NFD; [:Nonspacing Mark:] >; ::Any-NFC; ‘ < input.txt > output.txt

拆分文件,查看 split(按大小拆分)和 csplit(按模式拆分)。

使用 zless,zmore,zcat 和 zgrep對壓縮過的文件進行操作。

系統調試

對於 web 調試來說,curl 和 curl -I 都是很趁手的工具,它們的好基友 wget 也不錯,或者是更時尚一點的 httpie。

使用 iostat、netstat、top (htop 更佳)和 dstat 去獲取硬盤、cpu 和網絡的狀態。熟練掌握這些工具可以使你快速的對系統的當前狀態有一個大概了解。

若要對系統有一個深度的總體認識,使用 glances。它在一個終端窗口中向你提供一些系統級的數據。這對於快速的檢查各個子系統非常有幫助。

若要了解內存狀態,運行並理解 free 和 vmstat 的輸出。尤其註意“cached”的值,它指的是 Linux 內核用來作為文件緩存的內存大小,因此它與空閑內存無關。

Java 系統調試則是另一碼事了,不過有一個簡單的小技巧可以用於 Oracle 的 JVM 或其他 JVM ,運行 kill -3 <pid> 會將一個完整的棧軌跡和堆概述(包括 GC 的細節)保存到標準輸出/日誌文件。

使用 mtr 去跟蹤路由,用於確定網絡問題。

用 ncdu 來查看磁盤使用情況,它比常用的命令,如 du -sh *,更節省時間。

查找正在使用帶寬的套接字連接或進程,使用 iftop 或 nethogs。

ab 工具(捆綁於 Apache)可以簡單粗暴地檢查 web 服務器的性能。對於更復雜的負載測試,使用 siege。

wireshark,tshark 和 ngrep 可用於復雜的網絡調試。

了解 strace 和 ltrace。當你想知道程序運行失敗、掛起甚至崩潰的原因,或者你想對性能有個總體了解的話,這兩個工具十分管用。註意 profile 參數(-c)和附加到一個運行的進程參數 (-p)。

了解 ldd 命令來檢查共享庫等等。

知道如何用 gdb 來調試運行程序並獲取堆棧軌跡。

學會使用 /proc。它在調試正在出現的問題的時候有時會效果驚人。比如:/proc/cpuinfo,/proc/meminfo,/proc/cmdline,/proc/xxx/cwd,/proc/xxx/exe,/proc/xxx/fd/,/proc/xxx/smaps。

如果想調試已經發生的問題,sar 顯得很管用。它會列出CPU、內存、網絡等歷史統計數據。

關於更深層次的系統分析以及性能分析,看看 stap(SystemTap),perf,以及sysdig。

查看你當前使用的系統,使用 uname 或者 uname -a (Unix/kernel 信息) or lsb_release -a (Linux 發行版信息)。

如果某些問題看起來稍顯搞笑,試試查看 dmesg 信息(可能是硬件或驅動問題)。

一行命令

一些組合命令:

當你需要對文本文件做集合交、並、差運算時, sort/uniq 聯合出擊顯得非常管用。假設 a 與 b 是兩個內容不同且去重的文件。這種方式效率很高,並且對各種大小的文件都適用,不管是在小文件還是上G的大文件。(sort 不受內存約束,不過如果 /tmp 所處的根分區容量有限,你可能需要 -T 參數),參閱前文中關於 LC_ALL 和 sort 的 -u 參數的部分。

cat a b | sort | uniq > c # c is a union b

cat a b | sort | uniq -d > c # c is a intersect b

cat a b b | sort | uniq -u > c # c is set difference a - b

使用 grep . * 命令來檢查目錄下所有文件的內容,例如那些包含許多配置設置的目錄: /sys/, /proc/, /etc。

對文本文件中第三列數據計算總和(相比python 快三倍,代碼量卻只有 python 的1/3):

awk ‘{ x += $3 } END { print x }‘ myfile

如果想查看目錄樹中文件的大小或者日期,下面這條命令類似遞歸的 ls -l,但是輸出結果比 ls -lR 更易讀:

find . -type f -ls

Xargs 或者 parallel 命令也很管用。我們還可以使用 -L 或者 -P 選項限制每行參數個數。如果對執行結果不確定的話,可以先用 xargs echo 查看。同樣, -I{} 選項用起來也很順手。例如:【前面已經有了,內容重復】

find . -name ‘*.py‘ | xargs grep some_function

cat hosts | xargs -I{} ssh root@{} hostname

假設你有一個類似於 web 服務器日誌文件的文本文件,並且某個特定值只會出現在某些行上,比如會在 URL 中出現的 acct_id 參數。如果你想計算出每個 acct_id 值有多少次請求,使用如下代碼:

運行這個函數從這篇文檔中隨機獲取一條小技巧(解析 Markdown 文件並抽取項目):

function taocl() {

curl -s https://raw.githubusercontent.com/jlevy/the-art-of-command-line/master/README.md |

pandoc -f markdown -t html |

xmlstarlet fo --html --dropdtd |

xmlstarlet sel -t -v "(html/body/ul/li[count(p)>0])[$RANDOM mod last()+1]" |

xmlstarlet unesc | fmt -80

}

管用的小冷門

expr:計算表達式、布爾操作或正則匹配

m4:簡單地宏處理器

yes:多次打印字符串

cal:日歷

env:執行一個命令(腳本文件中很有用)

printenv: 打印環境變量(在調試時或者腳本中很管用)

look: 找出以某字符串開頭的英文單詞(或者文件中的某一行)

cut, paste 和 join :數據處理

fmt: 格式化文本段落

pr : 將文本格式化為頁數據或者列數據

fold : 封裝文本中的行【比如 -w 指定寬度,不使用默認的80】

Column: 將文本格式化為列或者表數據

expand 和 unexpand:制表符與空格之間轉換

nl:添加行號

seq:打印序列數字

bc:計算器

factor:分解因數 【例如 factor 100,輸出 2 2 5 5】

gpg:加密並簽名文件

toe:終端類型列表

nc:網絡調試及數據傳輸

socat:套接字代理,與 netcat 類似

slurm:網絡負載監視器

dd:在文件或設備間傳輸數據

file:確定文件類型

tree:以樹的形式顯示路徑和文件,類似於 ls,不過這條命令會遞歸顯示

stat:文件信息

time:執行命令,並計算執行時間

tac:反向輸出文件

Shuf :將文件中的數據隨機選擇排列

comm: 逐行比較已排序的文件

pv: 監控通過管道的數據

hd 和 bvi:保存或者編輯二進制文件

strings: 提取二進制文件的文本內容

Tr: 字符轉換與處理

Iconv 或 uconv: 文本編碼的轉換

Spit 和scplit : 分割文件

Sponge: 在寫之前讀取所有輸入,在對同一個文件讀寫很管用,例如: grep -v something some-file | sponge some-file 【將文件中所有匹配 something 的行都刪除】

units:單位轉化與計算;將一種計量單位轉換為另一種等效的計量單位(參閱 /usr/share/units/definitions.units)

7z: 一種高效的壓縮工具

Ldd: 查看動態庫的信息

Nm: 提取可執行文件或者 obj 文件的符號

Ab:web 服務器性能分析工具

Strace: 調試系統調用

Mtr:網絡調試跟蹤工具

Cssh: 可視化的並發 shell

Rsync :可用於遠程文件目錄同步

Wireshark 和 tshark : 抓取包與網絡調試

Ngrep: 網絡層的 grep 工具

Host 和 dig: DNS 查找

Lsof : 處理文件描述符和 socket 信息【列出所有打開的文件】

dstat : 通用的系統統計工具

glances:高層次的多子系統概覽

iostat:CPU 和硬盤使用狀態

htop:top 的加強版

last:登入歷史記錄

w:當前登陸用戶

id:用戶/組 ID 信息

sar: 系統歷史數據統計

iftop 或 nethogs:套接字及進程的網絡利用率

ss:套接字數據統計

dmesg:引導及系統錯誤信息

hdparm:SATA/ATA 磁盤操作及性能分析

lsb_release:Linux 發行版信息

lsblk:列出塊設備信息:樹狀圖展示你的磁盤以及磁盤分區信息

lshw,lscpu,lspci,lsusb 和 dmidecode:查看硬件信息,包括 CPU、BIOS、RAID、顯卡、其他設備等

fortune,ddate 和 sl:開個玩笑…… 如果對心靈雞湯或者奔跑的小火車感興趣的話,可以自己試試

僅限 MacOS

以下是僅限於 MacOS 系統的技巧

  • 用 brew (Homebrew)或者 port (MacPorts)進行包管理。這些可以用來在 Mac 系統上安裝以上的大多數命令。

  • 用 pbcopy 復制任何命令的輸出到桌面應用,用 pbpaste 粘貼輸入。

  • 用 open 或者 open -a /Applications/Whatever.app 使用桌面應用打開文件。

  • Spotlight: 用 mdfind 搜索文件,用 mdls 列出元數據(例如照片的 EXIF 信息)。

註意 MacOS 系統是基於 BSD UNIX 的,許多命令(例如 ps,ls,tail,awk,sed)都和 Linux 中有些微的不同,受 System V-style Unix 和 GNU 工具影響很大。你可以通過標題為 “BSD General Commands Manual” 的 man 頁面發現這些不同。在有些情況下 GNU 版本的命令也可能被安裝(例如 gawk 和 gsed 對應 GNU 中的 awk 和 sed )。如果要寫跨平臺的 Bash 腳本,避免使用這些命令(例如,考慮 Python 或者 perl )或者經過仔細的測試。

Linux -高階命令行技巧