Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

程式設計師聯盟發表於2017-04-08

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

-- 作者 謝恩銘 轉載請註明出處

內容簡介


  1. 第三部分第四課:後臺執行及合併多個終端
  2. 第三部分第五課預告:延時執行,唯慢不破

後臺執行及合併多個終端


上一課 Linux探索之旅 | 第三部分第三課:監視系統活動,滴水不漏 中,我們簡單介紹了程式,也學習瞭如何列出系統中的程式,如何過濾列表結果,還有如何結束程式。

這一課我們繼續乘勝追擊,一路向北,來學習程式的後臺執行。

我們使用的終端讓我們難免有一種感覺:我們每次只能在一個終端中執行一個程式。但其實這是大錯特錯的。

終端還可以執行後臺程式。要使一個程式在後臺執行,有幾種方法,我們都將學習。

這一課的第三節還將學習screen這個程式,用於同時開多個終端視窗。

&符號和nohup命令:後臺執行程式


我們到目前為止用終端做的事情都是眼目所能及的,也就是說:我們執行的命令都是在前臺可見的。

這樣有一個好處是我們可以看到命令執行的過程,有什麼問題可以及時發現。但是也有缺陷,例如有的命令執行耗時良久,我們又不想無所事事,怎麼辦呢?難道我開一個終端專門執行一個耗時命令,然後為了能做其他事情,我再啟動一個終端,那也很不方便。而且,這樣的規避方法在非圖形介面的終端(還記得我們的tty1~tty6嗎?)中是難以實現的,因為只有一個終端視窗。

所以這課顯得尤為重要。

事實上,我們可以在同一個終端中同時執行好幾個命令。怎麼做呢?就需要用到後臺程式的概念。

前臺程式和後臺程式


預設情況下,使用者建立的程式都是前臺程式。前臺程式從鍵盤讀取資料,並把處理結果輸出到顯示器。

我們可以看到前臺程式的執行過程。例如,使用 ls 命令來遍歷當前目錄下的檔案。

ls複製程式碼

這個程式就執行在前臺,它會直接把結果輸出到顯示器。如果 ls 命令需要資料(實際上不需要),那麼它會等待使用者從鍵盤輸入。

當程式執行在前臺時,由於命令提示符($)還未出現,使用者不能輸入其他命令;即使程式需要執行很長時間,也必須等待程式執行結束才能輸入其他命令。

後臺程式與鍵盤沒有必然的關係。當然,後臺程式也可能會等待鍵盤輸入。

後臺程式的優點是不必等待程式執行結束就可以輸入其他命令。

那麼怎麼使一個程式(程式的例項)執行在後臺呢?

&符號:在後臺執行程式


前面說過,讓一個程式在後臺執行有幾種方法。

我們帶大家來學習第一種,很簡單:就是在你要執行的命令最後加上&這個符號。

我們可以用熟悉的cp命令做例子。例如,我執行cp命令來拷貝檔案:emacs的軟體包。

cp emacs-24.4.tar.gz emacs-24.4-copy.tar.gz &複製程式碼

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

上圖中,因為命令最後加了&符號,執行時此程式就成為了後臺程式。終端輸出了一些資訊:

[1] 16525複製程式碼
  • [1]:這是此終端的後臺程式的標號。因為這是第一個後臺程式,所以標號為1。

  • 16525:這是程式號(PID),如果你想要結束這個後臺程式,你可以用我們上一課學習的kill命令:

    kill 16525複製程式碼

我們雖然看不到這個拷貝程式的“所作所為”,但它確實在後臺默默進行著檔案的拷貝。

如果我們用其他命令試一下,例如find命令,你會吃驚的。

例如我們執行:

find / -name "*log" &複製程式碼

意思是:在根目錄/下查詢所有以log結尾的檔名的檔案,並且在後臺執行此程式。

但是你會發現,find命令雖然在後臺執行了,但是終端還是會不斷顯示所有找到的內容或錯誤資訊。雖然我們還可以在終端中輸入其他命令,但是一直會跳出find搜尋的結果還是很讓人感到厭煩的。最後小編不得不把它停止(用kill命令)。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

幸好,我們之前學過重定向,我們可以把find的輸出結果重定向到檔案裡,就不會再來煩我們了。

find / -name "*log" > output_find &複製程式碼

這樣就不會一直有資訊輸出了。

當然了,我們還可以更保險一些,將標準錯誤輸出也重定向到同一個檔案,這樣就不會有任何輸出了。

find / -name "*log" > output_find 2>&1 &複製程式碼

但現在有一個問題:雖然我們的程式是被放到後臺了,在終端貌似看不到它的執行過程了。但是此程式還是與此終端相關聯的,假如我們把終端關閉,那麼這個程式也就會結束。

nohup命令:使程式與終端分離


&符號雖然常用,但卻有一個不可忽視的缺點:後臺程式與終端相關聯,一旦終端關閉或者使用者登出,程式就自動結束。

如果我們想讓程式在以上情況下仍然繼續在後臺執行,那麼我們須要用到nohup命令。

當使用者登出(logout)或者網路斷開時,終端會收到 HUP(是hangup的縮寫,英語《結束通話》的意思)訊號從而關閉其所有子程式;終端被關閉時也會關閉其子程式。

我們可以用nohup命令使命令不受HUP訊號影響。

我們用man來看一下nohup命令的解釋:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到,nohup命令的簡單描述如下:

run a command immune to hangups, with output to a not-tty複製程式碼

翻譯出來大致就是:使得執行的命令不受hangup訊號影響,而且輸出會存放到一個非tty中。

nohup命令的用法很簡單:在nohup命令之後接要執行的命令。例如:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到這次的輸出資訊是:ignoring input and appending output to nohup.out

大致意思是:忽略輸入,把輸出追加到nohup.out檔案中。

使用nohup命令後,輸出會被預設地追加寫入到一個叫nohup.out的檔案裡。

現在,我們的程式已經不受終端關閉或者使用者斷開連線的影響了,會一直執行。當然了,用kill命令還是可以結束此程式的。

nohup命令相當有用。想象以下場景:

我登入遠端伺服器,然後執行了一個耗時命令,或者一個需要一直執行的命令,例如一個遊戲的伺服器程式。這時假如我掉線了,或者我不小心用exit命令退出了登入。那麼這個耗時命令也會中止執行。那就很麻煩了。而且,如果這個程式本應該一直執行很久的,我也不可能一直保持登入狀態等它結束啊。
我家裡還有老婆孩子呢,不能不去做飯啊,我要下班。。。開個小玩笑。

幸好,nohup命令解決了這樣的難題。

Ctrl + Z,jobs,bg和fg命令:控制程式的前後臺切換


我們來考慮一種情況:假如你要將程式轉到後臺執行,但是執行命令時忘記了在最後加上&符號。

如何再使此程式轉為後臺程式呢?有幾種方法。我們一一來學習。

Ctrl + Z:轉到後臺,並暫停執行


我們用top命令來演示。執行:

top複製程式碼

因為top命令的作用是實時地顯示各種系統資訊和程式列表。這時,我們按下Ctrl + Z這個組合鍵:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到終端顯示了

[1]+ Stopped top複製程式碼

這行資訊。

stopped是英語《停止的》的意思,然後我們又看到[1]這個熟悉的資訊,表示這是此終端第一個後臺程式。

所以表示top命令被放到了後臺,此程式還是駐留在記憶體中,但是被暫停執行了。這個時候命令提示符又出現了,我們可以做其他事情了。

bg命令:使程式轉到後臺


經過上面的Ctrl + Z操作,我們可憐的top程式已經被“打入冷宮”(轉入後臺,並且被暫停執行了)。

但是皇后不甘心啊:“臣妾雖然做不到,但即使在冷宮中,我也要工於心計,運籌帷幄,以期早日打敗甄嬛”。

那怎麼辦呢?可以執行bg命令。

就是很簡單地輸入bg,然後回車。bg是英語background的縮寫,表示《後臺》。

bg命令的作用是將命令轉入後臺執行。假如命令已經在後臺,並且暫停著,那麼bg命令會將其狀態改為執行。

不加任何引數,bg命令會預設作用於最近的一個後臺程式,也就是剛才被Ctrl + Z暫停的top程式。如果後面加 %1,%2這樣的引數(不帶%,直接1,2這樣也可以),則是作用於指定標號的程式。因為程式轉入後臺之後,會顯示它在當前終端下的後臺程式編號。例如目前top程式轉入了後臺,它的程式編號是1(可以由[1]+推斷)。依次類推,bg %2就是作用於編號為2的後臺程式。

我們輸入bg,然後回車。看到如下輸出:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

上圖中,終端首先顯示了:

[1]+ top &複製程式碼

表示top命令被轉到了後臺,但是接著,它又顯示了這一條資訊:

[1]+ Stopped top複製程式碼

咦,為什麼top程式還是暫停著呢?anz理說bg命令會把在後臺暫停的程式重新喚醒,使之在後臺重新執行啊。

我們用ps命令來檢視一下程式資訊:

ps -aux複製程式碼

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

在上圖中可以看到,top這個程式的程式號是23051,狀態是T。

首先補充一些知識:

Linux中,程式有5種狀態:

  1. 執行 (正在執行或在執行佇列中等待)
  2. 中斷 (休眠中, 受阻, 在等待某個條件的形成或接受到訊號)
  3. 不可中斷 (收到訊號不喚醒和不可執行, 程式必須等待直到有中斷髮生)
  4. 僵死 (程式已終止, 但程式描述符存在, 直到父程式呼叫wait4()系統呼叫後釋放)
  5. 停止 (程式收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU訊號後停止執行執行)

ps命令標識程式的5種狀態碼:

  1. D 不可中斷 uninterruptible sleep (usually IO)
  2. R 執行 runnable (on run queue)
  3. S 中斷 sleeping
  4. T 停止 traced or stopped
  5. Z 僵死 a defunct ("zombie") process

因此,我們的top程式的狀態還是T,也就是停止(stopped)的狀態。很奇怪是嗎?

我們用其他的命令來測試看看。我們測試find命令。首先執行:

find / -name "*log" > find_log 2>&1複製程式碼

上面這個命令的作用是:在根目錄 / 下查詢以log結尾的檔案,將標準輸出和標準錯誤輸出都重定向到find_log檔案中。

因此,雖然上述命令在執行,但終端中看不到任何資訊。

我們用Ctrl + Z來暫停此程式,並將其轉到後臺。然後再執行bg命令,使其重新在後臺執行。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

奇怪了,為什麼bg作用於暫停的find命令後,並沒有像剛才top命令一樣仍然顯示Stopped呢?

我們再用ps -aux 看一下:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到,top命令的狀態是T,也就是停止(Stopped)。而find命令的狀態則是D,也即是不可中斷的睡眠(但其實是在執行,等會我們就會看到)。

疑問:所以小編也不清楚為什麼對普通的命令(例如find),bg命令是起作用的,會將其轉成後臺執行。
但是對於top命令,bg為什麼不能將其轉成後臺執行,可能是因為top命令本身比較特殊吧。
也許是因為top命令是前臺互動式命令,因此不能被置於後臺執行。

小結一下:

如果你本想要使一個命令執行在後臺,成為後臺程式,但是忘記加&符號了。那麼可以按下面的順序使此程式轉為後臺執行:

  • Ctrl + Z:使程式轉為後臺暫停。

  • bg:使程式轉為後臺執行。

那你也許要問:為什麼不直接用bg命令一步到位呢?

因為,如果不先用Ctrl + Z將此程式暫停,此程式就一直在前臺執行,你沒法在命令提示符後面輸入啊。

jobs命令:顯示後臺程式狀態


這個命令很強大,畢竟和賈伯斯喬老爺子(賈伯斯的英文就是jobs,全名是Steve Jobs。job是英語《工作》的意思,jobs就是job的複數形式)一樣名字麼。

jobs命令的作用是顯示當前終端裡的後臺程式狀態。雖然我們可以用ps命令來檢視程式狀態,但是ps命令輸出的程式列表太長了。

聰明如你一定想到了,我們可以用jobs命令來顯示剛才那兩個程式的狀態:top程式和find程式。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

jobs命令的輸出共分三列,我們逐列來說明:

  1. 顯示後臺程式標號:比如上例中top程式的標號是1,find程式的標號是2,如果還有其他後臺程式,那麼就會有[3],[4],等等。這個標號和PID(程式號)是不一樣的。這個標號只是顯示當前終端下的後臺程式的一個編號。

  2. 顯示後臺程式狀態:比如Stopped是停止的意思,Running是執行的意思。還有其他狀態。

  3. 命令本身。

可以看到,我們的top程式確實是在後臺暫停了,因為顯示Stopped,是英語《停止的》的意思。find程式在後臺執行,因為顯示Running,是英語《執行中》的意思。

fg命令:使程式轉到前臺


fg是英語foreground的意思,表示《前臺》。

與bg命令相反,fg命令的作用是:使程式轉為前臺執行。

用法也很簡單,和bg一樣,如果不加引數,那麼fg命令作用於最近的一個後臺程式。如果加引數,如%2,那麼表示作用於本終端中第二個後臺程式。

好了,講了這麼多知識點,是不是有點暈呢?沒關係。

我們用下面這個狀態圖來做個總結,應該就很清楚了:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

解釋一下上圖:

  1. 如果我們執行一個程式,預設情況下,它會成為一個前臺執行的程式。我們可以按組合鍵Ctrl + C來銷燬此程式。

  2. 我們也可以使此程式在後臺執行。假如執行程式時就用&放在命令最後,那麼程式就會在後臺執行。

  3. 假如在程式執行起來後,按Ctrl + Z,則程式會轉到後臺,並且停止。此時如果執行bg命令,則程式重新執行,並繼續在後臺。

  4. fg命令可以使程式轉到前臺,並且執行。

花點時間好好理解一下這個狀態圖。這個圖很重要,幾乎概括了後臺前臺程式切換的所有情況。

screen命令:合併多個終端


最後一節,我們來學習一個特殊的命令:screen

screen是英語“螢幕”的意思。

screen這個程式(所有命令其實都是程式)通常沒有在Linux發行版裡預裝,如果你的Ubuntu系統裡沒有screen這個程式,那麼可以如此安裝:

sudo apt-get install screen複製程式碼

安裝完之後,你可以輸入screen命令,回車,會顯示以下內容:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

按回車或空格跳過這個介紹頁面。

screen命令用於在一個終端中開啟多個終端,就好像在一個頁面中開多個標籤欄一樣(使用過瀏覽器的朋友肯定有這種使用經驗),很酷吧。

但是screen開啟的多個終端是重疊在一起的,如果你不知道,還以為只是開啟了一個終端,但是我們會學習如何在各個開啟的終端間切換。

在我們執行了screen命令後,再用Enter鍵跳過那頁介紹之後,我們看到終端裡好像沒發生什麼變化,就跟之前我們看到的終端一樣誒,那screen到底做了什麼呢?

其實,screen為我們開了一個虛擬終端,就是在當前實際的終端裡又開了一個終端。

如果你再執行screen,那麼它又會新開一個虛擬終端。那麼怎麼退出每個新開的虛擬終端呢?可以按Ctrl + D或者用exit命令。

每次你按Ctrl + D或執行exit命令,都會關閉當前所在的虛擬終端,直到最後一個虛擬終端被關閉,screen程式退出,回到我們的實際終端裡,如下圖:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

上圖顯示了[screen is terminating],表示所有screen開的虛擬終端都已關閉,screen退出(terminate是英語《終結,停止》的意思。施瓦辛格的電影《終結者》就是《The Terminator》)。

現在我們已經知道如何退出screen了。

我們重新回去吧,再輸入screen就好了。

在screen程式中,幾乎所有的操作都是以Ctrl + a開始的。

以下所有的講解中,英文字母區分大小寫。也就是說:b和B是不同的,前者就是按下鍵盤上的b鍵,B則是需要用Shift + b。

如何操作呢?首先,按下Ctrl + a鍵,然後鬆開Ctrl鍵和a鍵,再按其他鍵來完成一定的操作。

Ctrl + a再加?號:顯示幫助頁面


我們先用Ctrl + a鍵(也就是同時按下Ctrl鍵和a鍵),然後鬆開這兩個鍵,再按下?號(需要Shift + /號)。

screen的幫助頁面就會顯示:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到,幫助頁面顯示了各種操作的實現方法。(好好學英語,很有好處吧,可以參看 對於程式設計師, 為什麼英語比數學更重要? 如何學習

幫助頁總共有3頁,可以通過第一頁第一行[Screen key bingings,page 1 of 3]知道。目前是在3頁中的第一頁,按空格可以翻到下一頁,按回車退出幫助頁。

那怎麼來閱讀這個幫助頁面呢?

比如說,你想要知道screen的版本號,那就是version,可以看到需要用到v鍵。但是光是按v鍵還不夠,因為我們看到第一頁第二行Command key: ^A ,就是說以下所有的操作,都需要先按下Ctrl + a鍵。^表示Ctrl鍵。

所以說,要知道screen的版本號,可以先按Ctrl + a鍵(也就是同時按下Ctrl鍵和a鍵),然後鬆開這兩個鍵,再按下v鍵。就會在左下角顯示screen的版本號了。

當然了,這個幫助頁面還是不太容易懂,不過我們也不需要全部記住,只要會用常用的一些組合鍵就好了。

常用的組合按鍵


Ctrl + a,鬆開,再按c:建立一個新的虛擬終端。

Ctrl + a,鬆開,再按w:顯示當前虛擬終端的列表。會顯示在左下角,類似下圖:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

此處的 0$ bash 1-$ bash 2*$ bash 表示此時開啟了3個虛擬終端,都叫作bash,編號是0,1,2。

有*(星號)的那個虛擬終端就是我們目前所在的虛擬終端,也就是第3個,編號是2。

Ctrl + a,鬆開,再按A:重新命名當前虛擬終端。修改後的名字,你之後再用Ctrl + a,鬆開,再按w時就會看到。

Ctrl + a,鬆開,再按n:跳轉到下一個虛擬終端。

Ctrl + a,鬆開,再按p:跳轉到上一個虛擬終端。

Ctrl + a,鬆開,再按Ctrl + a:跳轉到最近剛使用的那個虛擬終端。

Ctrl + a,鬆開,再按0~9數字鍵:跳轉到第0~9號虛擬終端。

Ctrl + a,鬆開,再按 "(雙引號):會讓你選擇跳轉到哪個虛擬終端。

Ctrl + a,鬆開,再按k:關閉當前終端。

以上是一些常用的screen組合鍵,下面我們重點來看兩個很有用的組合鍵,分別用於分割虛擬終端和分離screen。

Ctrl + a,鬆開,再按S:分割虛擬終端為多個小虛擬終端


注意是大寫的S,所以是Shif + s。如果這樣操作一次,則當前虛擬終端被分割為上下兩部分。如下圖所示:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

如果再按這樣操作,就分割成3部分,4部分...

可以看到我在上面的半部分中執行了ls命令,下面的半部分暫時還沒跳轉過去操作,因此下半部分連命令列提示符也沒有,空空的。

那我們如何跳轉到下半部分去操作呢?

Ctrl + a,鬆開,再按Tab鍵。

游標就會跳轉到下半部分了,但是還是沒見有命令列提示符,那是因為還沒為下半部分建立虛擬終端呢。

所以我們可以新建一個:Ctrl + a,鬆開,再按c。或者開啟一個現有的虛擬終端。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到,我們用Ctrl + a,鬆開,再按c之後,下半部分的左下角的--變成了3 bash,說明新建了一個虛擬終端,編號是3,也就是第4個(虛擬終端的編號從0開始)。

我們在這個3 bash的虛擬終端裡執行top命令,如下:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

那麼我們如何關閉新分割出來的虛擬終端呢?只要Ctrl + a,鬆開,再按X(是大寫的X,也就是Shift + x)。

Ctrl + a,鬆開,再按d:分離screen


如果我們在screen程式中,先按Ctrl + a,鬆開,再按d,就可以使screen程式與當前實際終端分離了,有點類似nohup命令的作用。

這樣我們就可以重回我們自己的實際終端了,而screen並沒有退出,還在後臺執行。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到 [detached from 6815.pts-0.oscar-laptop]

表示我們的screen與實際終端分離(detach是英語《分離,掙脫》的意思)了。

之後如果你要重回screen中,可以輸入

screen -r複製程式碼

就又回到剛才的screen的虛擬終端裡了。

我們可以使好幾個screen進入分離(detached)狀態。

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

可以看到,我們繼剛才分離了編號6815的screen程式之後,現在又分離了一個編號13840的screen程式。

之後再執行screen -r想要回去的時候,因為有兩個screen分離程式了,實際終端會詢問你要回到哪一個,如下圖:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

你想要回到哪一個就用:

screen -r 編號複製程式碼

就可以了。例如我要回到6815那個screen,只要這樣:

screen -r 6815複製程式碼

如果你在實際終端下,輸入:

screen -ls複製程式碼

則會列出當前開啟著的screen程式:

Linux 探索之旅 | 第三部分第四課:後臺執行及合併多個終端

怎麼樣,screen是不是很有趣呢?好好練習,就會比較熟練了。

用過Emacs或Vim編輯器的讀者,也許覺得screen有點像Emcas或Vim中的一部分功能。

是有點像。不過,screen怎麼能和Emacs及Vim如此強大的編輯器相比呢。

總結


  1. 我們可以使程式在後臺執行,成為後臺程式。這樣在當前終端中我們就可以做其他事了,而不必等待此程式執行結束。

  2. 為了使一個程式在後臺執行,可以在命令的最後加上&這個符號。但是,如果你關閉終端或退出登入,此後臺程式還是會結束。為了將後臺程式與本終端分離,可以使用nohup命令,使得程式不再受終端關閉或使用者登出的影響。

  3. 如果你執行了一個前臺程式,但是想要將其轉為後臺執行程式。你可以先用Ctrl + Z組合按鍵將其轉為後臺暫停,然後執行bg命令使其在後臺重新執行。如果你要將一個後臺命令(不管它是後臺執行還是後臺暫停)重新轉為前臺執行,只要用fg命令就可以了。

  4. screen是一個程式,你可以用apt-get來安裝。screen命令使使用者能夠在一個終端中開啟多個虛擬終端。

第三部分第五課預告


今天的課就到這裡,一起加油吧!

下一課我們學習:Linux探索之旅 | 第三部分第五課:延時執行,唯慢不破


微信公眾號「程式設計師聯盟」ProgrammerLeague
我是謝恩銘,在巴黎奮鬥的軟體工程師。
我的簡介
我的經歷
熱愛生活,喜歡游泳,略懂烹飪。
人生格言:“向著標杆直跑”

相關文章