Linux 中的 &
如果閱讀過我之前的三篇文章(1、2、3),你會覺得掌握連接各個命令之間的連接符號用法也是很重要的。實際上,命令的用法並不難,例如 mkdir
、touch
和 find
也分別可以簡單概括為「建立新目錄」、「更新文件」和「在目錄樹中查找文件」而已。
但如果要理解
mkdir test_dir 2>/dev/null || touch images.txt && find . -iname "*jpg" > backup/dir/images.txt &
這一串命令的目的,以及為什麼要這樣寫,就沒有這麼簡單了。
關鍵之處就在於命令之間的連接符號。掌握了這些符號的用法,不僅可以讓你更好理解整體的工作原理,還可以讓你知道如何將不同的命令有效地結合起來,提高工作效率。
在這一篇文章和接下來的文章中,我會介紹如何使用 &
號和管道符號(|
)在不同場景下的使用方法。
幕後工作
我來舉一個簡單的例子,看看如何使用 &
號將下面這個命令放到後台運行:
cp -R original/dir/ backup/dir/
這個命令的目的是將 original/dir/
的內容遞歸地複製到 backup/dir/
中。雖然看起來很簡單,但是如果原目錄裡面的文件太大,在執行過程中終端就會一直被卡住。
所以,可以在命令的末尾加上一個 &
號,將這個任務放到後台去執行:
cp -R original/dir/ backup/dir/ &
任務被放到後台執行之後,就可以立即繼續在同一個終端上工作了,甚至關閉終端也不影響這個任務的正常執行。需要注意的是,如果要求這個任務輸出內容到標準輸出中(例如 echo
或 ls
),即使使用了 &
,也會等待這些輸出任務在前台運行完畢。
當使用 &
將一個進程放置到後台運行的時候,Bash 會提示這個進程的進程 ID。在 Linux 系統中運行的每一個進程都有一個唯一的進程 ID,你可以使用進程 ID 來暫停、恢復或者終止對應的進程,因此進程 ID 是非常重要的。
這個時候,只要你還停留在啟動進程的終端當中,就可以使用以下幾個命令來對管理後台進程:
jobs
命令可以顯示當前終端正在運行的進程,包括前台運行和後台運行的進程。它對每個正在執行中的進程任務分配了一個序號(這個序號不是進程 ID),可以使用這些序號來引用各個進程任務。
$ jobs
[1]- Running cp -i -R original/dir/* backup/dir/ &
[2]+ Running find . -iname "*jpg" > backup/dir/images.txt &
fg
命令可以將後台運行的進程任務放到前台運行,這樣可以比較方便地進行交互。根據jobs
命令提供的進程任務序號,再在前面加上%
符號,就可以把相應的進程任務放到前台運行。
$ fg %1 # 將上面序號為 1 的 cp 任務放到前台運行
cp -i -R original/dir/* backup/dir/
如果這個進程任務是暫停狀態,fg
命令會將它啟動起來。
- 使用
ctrl+z
組合鍵可以將前台運行的任務暫停,僅僅是暫停,而不是將任務終止。當使用fg
或者bg
命令將任務重新啟動起來的時候,任務會從被暫停的位置開始執行。但 sleep 命令是一個特例,sleep
任務被暫停的時間會計算在sleep
時間之內。因為sleep
命令依據的是系統時鐘的時間,而不是實際運行的時間。也就是說,如果運行了sleep 30
,然後將任務暫停 30 秒以上,那麼任務恢復執行的時候會立即終止並退出。 bg
命令會將任務放置到後台執行,如果任務是暫停狀態,也會被啟動起來。
$ bg %1
[1]+ cp -i -R original/dir/* backup/dir/ &
如上所述,以上幾個命令只能在同一個終端里才能使用。如果啟動進程任務的終端被關閉了,或者切換到了另一個終端,以上幾個命令就無法使用了。
如果要在另一個終端管理後台進程,就需要其它工具了。例如可以使用 kill 命令從另一個終端終止某個進程:
kill -s STOP <PID>
這裡的 PID 就是使用 &
將進程放到後台時 Bash 顯示的那個進程 ID。如果你當時沒有把進程 ID 記錄下來,也可以使用 ps
命令(代表 process)來獲取所有正在運行的進程的進程 ID,就像這樣:
ps | grep cp
執行以後會顯示出包含 cp
字元串的所有進程,例如上面例子中的 cp
進程。同時還會顯示出對應的進程 ID:
$ ps | grep cp
14444 pts/3 00:00:13 cp
在這個例子中,進程 ID 是 14444,因此可以使用以下命令來暫停這個後台進程:
kill -s STOP 14444
注意,這裡的 STOP
等同於前面提到的 ctrl+z
組合鍵的效果,也就是僅僅把進程暫停掉。
如果想要把暫停了的進程啟動起來,可以對進程發出 CONT
信號:
kill -s CONT 14444
這個給出一個可以向進程發出的常用信號列表。如果想要終止一個進程,可以發送 TERM
信號:
kill -s TERM 14444
如果進程不響應 TERM
信號並拒絕退出,還可以發送 KILL
信號強制終止進程:
kill -s KILL 14444
強制終止進程可能會有一定的風險,但如果遇到進程無節制消耗資源的情況,這樣的信號還是能夠派上用場的。
另外,如果你不確定進程 ID 是否正確,可以在 ps
命令中加上 x
參數:
$ ps x| grep cp
14444 pts/3 D 0:14 cp -i -R original/dir/Hols_2014.mp4
original/dir/Hols_2015.mp4 original/dir/Hols_2016.mp4
original/dir/Hols_2017.mp4 original/dir/Hols_2018.mp4 backup/dir/
這樣就可以看到是不是你需要的進程 ID 了。
最後介紹一個將 ps
和 grep
結合到一起的命令:
$ pgrep cp
8
18
19
26
33
40
47
54
61
72
88
96
136
339
6680
13735
14444
pgrep
可以直接將帶有字元串 cp
的進程的進程 ID 顯示出來。
可以加上一些參數讓它的輸出更清晰:
$ pgrep -lx cp
14444 cp
在這裡,-l
參數會讓 pgrep
將進程的名稱顯示出來,-x
參數則是讓 pgrep
完全匹配 cp
這個命令。如果還想了解這個命令的更多細節,可以嘗試運行 pgrep -ax
。
總結
在命令的末尾加上 &
可以讓我們理解前台進程和後台進程的概念,以及如何管理這些進程。
在 UNIX/Linux 術語中,在後台運行的進程被稱為 守護進程 。如果你曾經聽說過這個詞,那你現在應該知道它的意義了。
和其它符號一樣,&
在命令行中還有很多別的用法。在下一篇文章中,我會更詳細地介紹。
via: https://www.linux.com/blog/learn/2019/2/and-ampersand-and-linux
作者:Paul Brown 選題:lujun9972 譯者:HankChow 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive