關于本系列
通常,UNIX® 管理員都擁有一套他/她經常使用協助管理進程的實用程序、技巧和系統。有一些重要的實用程序、命令行鏈以及腳本可用來簡化各種處理過程。這些工具中有一部分來自于操作系統,而大部分的技巧則來源于長期的經驗和簡化系統管理員工作的要求。本系列文章主要專注于最大限度地利用各種 UNIX 環境中可用的工具,包括簡化異類環境中的管理任務的方法。
使用 ps
ps
命令行工具列出了正在運行的進程。該工具存在于所有的 UNIX 變種中,并且大體上都按相同的基本方式工作,即向內核請求正在運行的進程列表,然后報告進程列表及其屬性,如內存使用情況、運行時間和其他詳細信息。
ps
工具實際上是一個非常強大的工具,盡管許多管理員可能僅使用可用選項中的某一兩項來查看所需的信息??梢岳脙戎妹钚羞x項從命令中獲取更多的信息,甚至可以將 ps
通過管道與其他命令結合起來,以獲取所需的準確信息。
列出所有進程
即使是以 root 身份登錄,ps
的標準輸出也只列出了您所運行的進程。根據您的 UNIX 環境是基于 BSD 或者 AT&T,SysV UNIX 基礎部分對用來獲取系統中其他進程信息的基本命令行選項做出相應的變動,或者改變所顯示的信息。在基于 BSD 的 UNIX 環境中,輸出包括進程 ID、終端、狀態、時間(在 CPU 中的執行時間,單位為秒,而不是進程開始運行的時間),以及所執行的命令,如清單 1 所示。
|
在 SVR4 環境中,所提供的列較少(您得不到進程狀態信息),如下面的清單 2 所示。
|
要獲取系統中正在運行的所有進程的列表,需要根據所使用的 UNIX 變種來使用不同的命令行選項。在 BSD UNIX 中,-a
命令行選項列出了包括您自己在內的所有用戶的進程。然而,這個列表并不會包括那些沒有控制終端的進程(比如那些在啟動時開始執行的進程、守護進程以及那些作為 cron
工作的一部分的進程)。要獲取所有正在運行的進程的列表,必須使用 -A
命令行選項(請參閱清單 3)。
|
-A
命令行選項與同時使用 -a
和 -x
選項等效,其中 -a
顯示擁有控制終端的進程,-x
顯示沒有控制終端的進程。
在 SVR4 變種中,顯示所有正在運行的進程(不論它是否擁有控制終端)的命令行選項是 -e
。從所顯示的進程來看,它和 BSD 的 -A
選項是等價的??梢栽?font color="#996699">清單 4 中看到輸出的示例。
|
輸出的區別在于所顯示的信息列,但是可以通過指定所需要的列來進行修改。
列出指定信息
ps
工具包含許多標準的顯示列集。例如在 SVR4 中,經常使用 ps -ef
來獲取關于列出進程的更詳細的信息,包括父進程 ID、處理器利用率、開始時間以及更詳細的命令行,如清單 5 所示。
|
對于 BSD 環境,通常添加 -l
選項,它為每個進程產生“長”輸出,如清單 6 所示。
|
這些選項存在的問題是,盡管它們顯示了更多的信息,但這些信息并不總是特別有用,或者在尋找某個特定進程時包含了不希望看到的擾亂顯示的信息。
幸運的是,所有版本的 ps
還包括了指定要顯示的列的功能??梢詮V泛地使用這種命令,不管是僅提取所需要的信息,還是在異類環境中使用它來創造標準化的跨不同 UNIX 環境的輸出。
要使用這一特性,可使用 -o
命令行選項,并列出要顯示的列,以逗號做列的分隔符。盡管可選擇的列的范圍有一些差別,但在不同的 UNIX 版本中,大部分列都是標準的。例如,所有變種中都有 pid、ppid(父進程 ID)、command、RSS(駐留集大小或內存使用情況)以及 priority。
使用時,可以用 -o
來選擇列及其顯示順序。例如,要獲取 pid、ppid 和 commond,在 BSD 中可以使用 -opid,ppid,command
,如清單 7 所示,或者在 SVR4 中使用 -opid,ppid,comm
,如清單 8 所示。
|
|
選擇了想要的列后,可能會選擇信息的排列順序。ps
的缺省設置是根據進程 ID 來排列進程列表,但是這樣可能會隱藏正在查找的信息。當查找內存饑餓的進程時,按內存使用量來排列顯示結果比按進程 ID 更加有用。
有些 ps
變種通過使用命令行選項來支持這種情況。BSD 變種中使用 -m
選項來按內存使用情況排序,或者使用 -r
來按 CPU 使用情況排序。許多 SVR4 變種沒有該問題的明確解決辦法,但是可以在所有環境中通過將 ps
和 sort
進行組合來生成類似的結果。例如,要獲取按 CPU 使用量排序的進程列表,可以在 BSD 中使用清單 9 所示的命令。
|
在 SVR4 中,需要將 %cpu
改為 pcpu
,而該命令在其他方面是相同的(請參見清單 10)。
|
該命令鏈是可行的,因為已經指定了進程列表的排列順序,因此可以按照這些列進行排序以獲取真正想要的信息。如果想使用不同的標準來查找進程,還有其他的可用方案。
列出特定進程
顯然,在獲取了正在運行的進程列表之后,也許希望列出特定的進程。一個顯而易見的方法就是將 ps
的輸出與 grep
結合起來,以提取所需的信息。在一些 UNIX 變種中,可以通過一些特定的實用程序來完成這項工作,例如 pgrep
,但是如果要查找一些特定的命令,使用 grep
也同樣是很有效的。
|
ps
命令還支持根據更明確的標準來顯示進程,例如用戶 ID、父進程或控制終端。例如,-U
命令行選項限定了進程列表只顯示指定用戶名的進程。例如,要顯示當前屬于 root 用戶的進程,請參閱清單 11。
|
要獲取指定終端的所有進程,使用 -t
,如清單 12 所示。
|
在有了這些信息后,也許想要用它來對進程進行相應的操作。
向多個線程發送信號
當找到了要查詢的進程后,最常用的命令之一是 kill
。它向一個或多個進程發送特定的信號。對于啟動了多個線程或子線程的守護進程的情況,可以嘗試向父進程發送信號,以此向所有的進程發送信號。然而,這種方法并不是對所有的守護進程和應用程序都有效。
顯然,您希望避免手動挑選出這些進程。有些 UNIX 變種中有一個名為 pkill
的工具,它能夠向滿足特定模式或其他標準的進程(例如終端、進程組、用戶 ID 以及組 ID 列表)發送相同的信號。
可以通過鏈接 ps
、grep
、awk
、xargs
以及 kill
命令的方式來模擬這一基本操作,向滿足特定命令模式的多個進程發送信號。例如,要向所有命令中包含“httpd”的進程發送 kill
信號,可以使用:
|
如果對單個元素進行研究,將更容易理解它。
|
該命令顯示了所有正在運行的進程的列表(這是在 SVR4 系統中,而在 BSD 中則應使用 -A
)。它僅顯示了進程 ID 和被執行的命令。不需要任何其他的信息,而且使用更詳細的輸出可能會引入其他方面符合搜索條件的文本。
|
該命令僅提取了命令中含有 httpd 的進程(因為進程列表中產生的唯一其他信息是進程 ID):
|
通過使用 awk
,僅篩選除去打印輸出中的第一個參數,即進程 ID。
|
xargs
命令接收空白字符分隔的項目列表(其中空白字符包括回車、換行、制表符以及一個或多個空格),并把它格式化為參數列表傳遞給指定的命令,在本示例中是 kill
命令。
最好把它放進腳本程序中,并取一個適當的名字,例如(pkill
或者 killbyname
)??梢栽O置該腳本接收兩個參數,信號和匹配文本,甚至還可以考慮操作系統的差別,如清單 13 所示。
|
這里所顯示的基本技術可以用于其他類似的排序規則。
計算內存使用情況
ps
工具還提供了我們目前尚未涉及的兩個列。RSS 列提供了進程的“駐留集大小”,這是該進程所使用的物理內存量,也是進程占用多少實際內存的指示。VSZ 列詳細列出進程正在使用的內存總量,包括所分配的內部存儲,但通常已被交換到磁盤。對于大多數 ps
變體而言,這兩個列都是比較常用的。
確定這兩個數據能夠更好地了解內存的使用情況。如果將 ps
與 grep
組合起來選擇特定的進程,并使用 awk
來計算總量,就可以獲取單個應用程序或者某個應用程序及其子進程正占用多少物理內存和虛擬內存。
例如,要確定 bash
進程所使用的物理內存和虛擬內存,可以使用清單 14 中的命令。
|
這在診斷內存和交換區使用情況的問題時特別有用。
使用與作業控制兼容的 Shell
對于一個典型的系統管理員來說,在任一時刻運行一或兩個以上的特定任務是很平常的事。盡管在任何時刻與服務器的連接可能不止一個,不論是多終端窗口(例如通過 xterm)還是其他的終端,或者通過 SSH、Telnet 的遠程連接,有時候需要在活動的 Shell 或者環境中控制或監視多個進程。
所有的 Shell 都支持在命令的末尾附加連字符 (&) 來使命令自動在后臺運行。但有時希望將一個交互應用程序(如一個編輯器)放到后臺,以便可以運行一個 Shell 命令,然后返回到編輯器會話。
這種控制后臺進程的能力稱為作業控制,它是 Korn Shell、C Shell 以及開源的 Shell(例如 bash 和 zsh)的標準特性。
為了實現在 Shell 中每次啟動一個命令時在后臺運行的基本作業控制,命令(可以是任何合法的命令行,甚至是內聯腳本)給出了作業引用 ID。
|
可以使用 jobs
命令獲取正在后臺運行的作業列表,如清單 15 所示。
|
在該清單中,第二個 emacs
命令使用了 + 號標注。這表示 Shell 認為它是當前的活動作業。先前啟動的 find
不是活動的工作,因為它不需要進行交互(盡管它產生輸出,它并不需要輸入來繼續),因而不是活動的進程。第一個 emacs 進程使用了 --
標注,說明 Shell 認為它先前是活動的命令??梢苑謩e使用 %+
和 %-
字符串來引用這些作業。
可以通過在 fg
后輸入作業編號或者作業字符串(%+
、%-
)來將任何正在運行的作業切換為前臺進程。如果省略了引用,Shell 就切換到當前的活動工作。
要掛起當前運行的進程,按 Control-Z??梢允褂孟旅娴拇a進行重新配置:
|
它可以和許多不同的命令及應用程序一起使用。對于在 Shell 中運行的大部分簡單命令,如 ls
或者 find
,它也應該是有效的。請注意,該作業被標記為 Stopped。這意味著已經暫停了該命令的執行。要將該命令切換為后臺進程,使用 bg
命令。與 fg
一樣,bg
接受作業引用或者在不帶參數時缺省為當前活動的作業作為其參數。如果該命令需要輸入(如編輯器、FTP 等),在 bg
命令之后再次按下回車時,會被警告該進程已暫時掛起(請參見清單 16)。
|
請注意,如果后臺命令產生了輸出,并且沒有將其重定向,那么即使通過作業控制將該命令放到后臺,它依然會輸出到屏幕。
在一個繁忙的環境中,作業控制就成了管理和控制多個后臺作業,或者快速退出編輯器和其他命令并返回到活動 Shell(相對與運行一個新的 Shell)的最簡便方法之一。
![]() |
|
在后臺可靠地運行進程
有時會想要在后臺運行腳本、實用程序或命令行。然而,大部分系統在用戶斷開連接或注銷時將終止在后臺運行的命令,如果想要先登錄,啟動命令,然后再注銷,這時會發現并不是想要的結果。
如果需要重新啟動,或者重新初始化后臺或沒有自動進行守護的守護進程,或者依賴于獨立的腳本來開始和管理守護應用程序的執行,在這些情況下命令執行的終止是非常讓人沮喪的。MySQL mysqld_safe
腳本是一個很好的例子,它正是以這種方式進行工作的。
要防止應用程序在您注銷時自動終止,可以使用 nohup
命令作為要運行的命令行或工具的前綴,如下所示:
|
除非專門為命令的輸出進行重定向,否則 nohup
自動將標準輸出和標準錯誤寫入當前目錄下名為 nohup.out
的文件中。
使用標準重定向可以輸出到自己的文件,但請記住,要同時重定向輸出和錯誤流,例如:
|
我發現自己總是無意識地使用 nohup
來運行任何我認為持續時間將長于 2、3 分鐘的命令,即使是在控制臺中運行該命令。這可能在很大程度上和輸出的自動重定向有關,而不是在連接失敗時防止終止的能力。