歡迎光臨
每天分享高質量文章

Linux 中的 & | Linux 中國

這篇文章將瞭解一下 & 符號及它在 Linux 命令列中的各種用法。

— Paul Brown

 

如果閱讀過我之前的三篇文章(1[1]2[2]3[3]),你會覺得掌握連線各個命令之間的連線符號用法也是很重要的。實際上,命令的用法並不難,例如 mkdirtouch 和 find 也分別可以簡單概括為“建立新目錄”、“更新檔案”和“在目錄樹中查詢檔案”而已。

但如果要理解

  1. mkdir test_dir 2>/dev/null || touch images.txt && find . -iname "*jpg" > backup/dir/images.txt &

這一串命令的目的,以及為什麼要這樣寫,就沒有這麼簡單了。

關鍵之處就在於命令之間的連線符號。掌握了這些符號的用法,不僅可以讓你更好理解整體的工作原理,還可以讓你知道如何將不同的命令有效地結合起來,提高工作效率。

在這一篇文章和接下來的文章中,我會介紹如何使用 & 號和管道符號(|)在不同場景下的使用方法。

幕後工作

我來舉一個簡單的例子,看看如何使用 & 號將下麵這個命令放到後臺執行:

  1. cp -R original/dir/ backup/dir/

這個命令的目的是將 original/dir/ 的內容遞迴地複製到 backup/dir/ 中。雖然看起來很簡單,但是如果原目錄裡面的檔案太大,在執行過程中終端就會一直被卡住。

所以,可以在命令的末尾加上一個 & 號,將這個任務放到後臺去執行:

  1. cp -R original/dir/ backup/dir/ &

任務被放到後臺執行之後,就可以立即繼續在同一個終端上工作了,甚至關閉終端也不影響這個任務的正常執行。需要註意的是,如果要求這個任務輸出內容到標準輸出中(例如 echo 或 ls),即使使用了 &,也會等待這些輸出任務在前臺執行完畢。

當使用 & 將一個行程放置到後臺執行的時候,Bash 會提示這個行程的行程 ID。在 Linux 系統中執行的每一個行程都有一個唯一的行程 ID,你可以使用行程 ID 來暫停、恢復或者終止對應的行程,因此行程 ID 是非常重要的。

這個時候,只要你還停留在啟動行程的終端當中,就可以使用以下幾個命令來對管理後臺行程:

◈ jobs 命令可以顯示當前終端正在執行的行程,包括前臺執行和後臺執行的行程。它對每個正在執行中的行程任務分配了一個序號(這個序號不是行程 ID),可以使用這些序號來取用各個行程任務。

  1. $ jobs
  2. [1]- Running cp -i -R original/dir/* backup/dir/ &
  3. [2]+ Running find . -iname "*jpg" > backup/dir/images.txt &
◈ fg 命令可以將後臺執行的行程任務放到前臺執行,這樣可以比較方便地進行互動。根據 jobs命令提供的行程任務序號,再在前面加上 % 符號,就可以把相應的行程任務放到前臺執行。

  1. $ fg %1 # 將上面序號為 1 cp 任務放到前臺執行
  2. cp -i -R original/dir/* backup/dir/

如果這個行程任務是暫停狀態,fg 命令會將它啟動起來。

◈ 使用 ctrl+z 組合鍵可以將前臺執行的任務暫停,僅僅是暫停,而不是將任務終止。當使用 fg 或者 bg 命令將任務重新啟動起來的時候,任務會從被暫停的位置開始執行。但 sleep[4] 命令是一個特例,sleep 任務被暫停的時間會計算在 sleep 時間之內。因為 sleep 命令依據的是系統時鐘的時間,而不是實際執行的時間。也就是說,如果運行了 sleep 30,然後將任務暫停 30 秒以上,那麼任務恢復執行的時候會立即終止並退出。
◈ bg 命令會將任務放置到後臺執行,如果任務是暫停狀態,也會被啟動起來。

  1. $ bg %1
  2. [1]+ cp -i -R original/dir/* backup/dir/ &

如上所述,以上幾個命令只能在同一個終端裡才能使用。如果啟動行程任務的終端被關閉了,或者切換到了另一個終端,以上幾個命令就無法使用了。

如果要在另一個終端管理後臺行程,就需要其它工具了。例如可以使用 kill[5] 命令從另一個終端終止某個行程:

  1. kill -s STOP <PID>

這裡的 PID 就是使用 & 將行程放到後臺時 Bash 顯示的那個行程 ID。如果你當時沒有把行程 ID 記錄下來,也可以使用 ps 命令(代表 process)來獲取所有正在執行的行程的行程 ID,就像這樣:

  1. ps | grep cp

執行以後會顯示出包含 cp 字串的所有行程,例如上面例子中的 cp 行程。同時還會顯示出對應的行程 ID:

  1. $ ps | grep cp
  2. 14444 pts/3 00:00:13 cp

在這個例子中,行程 ID 是 14444,因此可以使用以下命令來暫停這個後臺行程:

  1. kill -s STOP 14444

註意,這裡的 STOP 等同於前面提到的 ctrl+z 組合鍵的效果,也就是僅僅把行程暫停掉。

如果想要把暫停了的行程啟動起來,可以對行程發出 CONT 訊號:

  1. kill -s CONT 14444

這個給出一個可以向行程發出的常用訊號[6]串列。如果想要終止一個行程,可以傳送 TERM 訊號:

  1. kill -s TERM 14444

如果行程不響應 TERM 訊號並拒絕退出,還可以傳送 KILL 訊號強制終止行程:

  1. kill -s KILL 14444

強制終止行程可能會有一定的風險,但如果遇到行程無節制消耗資源的情況,這樣的訊號還是能夠派上用場的。

另外,如果你不確定行程 ID 是否正確,可以在 ps 命令中加上 x 引數:

  1. $ ps x| grep cp
  2. 14444 pts/3 D 0:14 cp -i -R original/dir/Hols_2014.mp4
  3. original/dir/Hols_2015.mp4 original/dir/Hols_2016.mp4
  4. original/dir/Hols_2017.mp4 original/dir/Hols_2018.mp4 backup/dir/

這樣就可以看到是不是你需要的行程 ID 了。

最後介紹一個將 ps 和 grep 結合到一起的命令:

  1. $ pgrep cp
  2. 8
  3. 18
  4. 19
  5. 26
  6. 33
  7. 40
  8. 47
  9. 54
  10. 61
  11. 72
  12. 88
  13. 96
  14. 136
  15. 339
  16. 6680
  17. 13735
  18. 14444

pgrep 可以直接將帶有字串 cp 的行程的行程 ID 顯示出來。

可以加上一些引數讓它的輸出更清晰:

  1. $ pgrep -lx cp
  2. 14444 cp

在這裡,-l 引數會讓 pgrep 將行程的名稱顯示出來,-x 引數則是讓 pgrep 完全匹配 cp 這個命令。如果還想瞭解這個命令的更多細節,可以嘗試執行 pgrep -ax

總結

在命令的末尾加上 & 可以讓我們理解前臺行程和後臺行程的概念,以及如何管理這些行程。

在 UNIX/Linux 術語中,在後臺執行的行程被稱為守護行程daemon。如果你曾經聽說過這個詞,那你現在應該知道它的意義了。

和其它符號一樣,& 在命令列中還有很多別的用法。在下一篇文章中,我會更詳細地介紹。

贊(0)

分享創造快樂