十九. 和系統運作程序相關的Shell指令:
1. 程序監控指令(ps):
要對程序進行監測和控制,首先必須要了解目前程序的情況,也就是需要檢視目前程序,而ps指令就是最基本同時也是非常強大的程序檢視指令。使用該指令可以确定有哪些程序正在運作和運作的狀态、程序是否結束、程序有沒有僵死、哪些程序占用了過多的資源等等。總之大部分資訊都是可以通過執行該指令得到的。
ps指令存在很多的指令行選項和參數,然而我們最為常用隻有兩種形式,這裡先給出與它們相關的選項和參數的含義:
選項
說明
a
顯示終端上的所有程序,包括其他使用者的程序。
u
以使用者為主的格式來顯示程式狀況。
x
顯示所有程式,不以終端來區分。
-e
顯示所有程序。
o
其後指定要輸出的列,如user,pid等,多個列之間用逗号分隔。
-p
後面跟着一組pid的清單,用逗号分隔,該指令将隻是輸出這些pid的相關資料。
/> ps aux
root 1 0.0 0.1 2828 1400 ? Ss 09:51 0:02 /sbin/init
root 2 0.0 0.0 0 0 ? S 09:51 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 09:51 0:00 [migration/0]
... ...
/> ps -eo user,pid,%cpu,%mem,start,time,command | head -n 4
USER PID %CPU %MEM STARTED TIME COMMAND
root 1 0.0 0.1 09:51:08 00:00:02 /sbin/init
root 2 0.0 0.0 09:51:08 00:00:00 [kthreadd]
root 3 0.0 0.0 09:51:08 00:00:00 [migration/0]
這裡需要說明的是,ps中存在很多和程序性能相關的參數,它們均以輸出表格中的列的方式顯示出來,在這裡我們隻是給出了非常常用的幾個參數,至于更多參數,我們則需要根據自己應用的實際情況去看ps的man手冊。
#以完整的格式顯示pid為1(init)的程序的相關資料
/> ps -fp 1
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 05:16 ? 00:00:03 /sbin/init
2. 改變程序優先級的指令(nice和renice):
該Shell指令最常用的使用方式為:nice [-n <優先等級>][執行指令],其中優先等級的範圍從-20-19,其中-20最高,19最低,隻有系統管理者可以設定負數的等級。
#背景執行sleep 100秒,同時在啟動時将其nice值置為19
/> nice -n 19 sleep 100 &
[1] 4661
#背景執行sleep 100秒,同時在啟動時将其nice值置為-19
/> nice -n -19 sleep 100 &
[2] 4664
#關注ps -l輸出中用黃色高亮的兩行,它們的NI值和我們執行是設定的值一緻。
/> ps -l
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 2833 2829 0 80 0 - 1739 - pts/2 00:00:00 bash
0 S 0 4661 2833 0 99 19 - 1066 - pts/2 00:00:00 sleep
4 S 0 4664 2833 0 61 -19 - 1066 - pts/2 00:00:00 sleep
4 R 0 4665 2833 1 80 0 - 1231 - pts/2 00:00:00 ps
renice指令主要用于為已經執行的程序重新設定nice值,該指令包含以下幾個常用選項:
-g
使用程式群組名稱,修改所有隸屬于該程式群組的程式的優先權。
改變該程式的優先權等級,此參數為預設值。
-u
指定使用者名稱,修改所有隸屬于該使用者的程式的優先權。
#切換到stephen使用者下執行一個背景程序,這裡sleep程序将在背景睡眠1000秒。
/> su stephen
/> sleep 1000&
[1] 4812
/> exit #退回到切換前的root使用者
#檢視已經啟動的背景sleep程序,其ni值為0,宿主使用者為stephen
/> ps -eo user,pid,ni,command | grep stephen
stephen 4812 0 sleep 1000
root 4821 0 grep stephen
#以指定使用者的方式修改該使用者下所有程序的nice值
/> renice -n 5 -u stephen
500: old priority 0, new priority 5
#從再次執行ps的輸出結果可以看出,該sleep背景程序的nice值已經調成了5
/> ps -eo user,pid,ni,command | grep stephen
stephen 4812 5 sleep 1000
root 4826 0 grep stephen
#以指定程序pid的方式修改該程序的nice值
/> renice -n 10 -p 4812
4812: old priority 5, new priority 10
#再次執行ps,該sleep背景程序的nice值已經從5變成了10
stephen 4812 10 sleep 1000
root 4829 0 grep stephen
3. 列出目前系統打開檔案的工具(lsof):
lsof(list opened files),其重要功能為列舉系統中已經被打開的檔案,如果沒有指定任何選項或參數,lsof則列出所有活動程序打開的所有檔案。衆所周知,linux環境中任何事物都是檔案,如裝置、目錄、sockets等。是以,用好lsof指令,對日常的linux管理非常有幫助。下面先給出該指令的常用選項:
-a
該選項會使後面選項選出的結果清單進行and操作。
-c command_prefix
顯示以command_prefix開頭的程序打開的檔案。
-p PID
顯示指定PID已打開檔案的資訊
+d directory
從檔案夾directory來搜尋(不考慮子目錄),列出該目錄下打開的檔案資訊。
+D directory
從檔案夾directory來搜尋(考慮子目錄),列出該目錄下打開的檔案資訊。
-d num_of_fd
以File Descriptor的資訊進行比對,可使用3-10,表示範圍,3,10表示某些值。
-u user
顯示某使用者的已經打開的檔案,其中user可以使用正規表達式。
-i
監聽指定的協定、端口、主機等的網絡資訊,格式為:[proto][@host|addr][:svc_list|port_list]
#檢視打開/dev/null檔案的程序。
/> lsof /dev/null | head -n 5
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root 0u CHR 1,3 0t0 3671 /dev/null
init 1 root 1u CHR 1,3 0t0 3671 /dev/null
init 1 root 2u CHR 1,3 0t0 3671 /dev/null
udevd 397 root 0u CHR 1,3 0t0 3671 /dev/null
#檢視打開22端口的程序
/> lsof -i:22
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1582 root 3u IPv4 11989 0t0 TCP *:ssh (LISTEN)
sshd 1582 root 4u IPv6 11991 0t0 TCP *:ssh (LISTEN)
sshd 2829 root 3r IPv4 19635 0t0 TCP bogon:ssh->bogon:15264 (ESTABLISHED)
#檢視init程序打開的檔案
/> lsof -c init
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
init 1 root cwd DIR 8,2 4096 2 /
init 1 root rtd DIR 8,2 4096 2 /
init 1 root txt REG 8,2 136068 148567 /sbin/init
init 1 root mem REG 8,2 58536 137507 /lib/libnss_files-2.12.so
init 1 root mem REG 8,2 122232 186675 /lib/libgcc_s-4.4.4-20100726.so.1
init 1 root mem REG 8,2 141492 186436 /lib/ld-2.12.so
init 1 root mem REG 8,2 1855584 186631 /lib/libc-2.12.so
init 1 root mem REG 8,2 133136 186632 /lib/libpthread-2.12.so
init 1 root mem REG 8,2 99020 180422 /lib/libnih.so.1.0.0
init 1 root mem REG 8,2 37304 186773 /lib/libnih-dbus.so.1.0.0
init 1 root mem REG 8,2 41728 186633 /lib/librt-2.12.so
init 1 root mem REG 8,2 286380 186634 /lib/libdbus-1.so.3.4.0
init 1 root 0u CHR 1,3 0t0 3671 /dev/null
init 1 root 1u CHR 1,3 0t0 3671 /dev/null
init 1 root 2u CHR 1,3 0t0 3671 /dev/null
init 1 root 3r FIFO 0,8 0t0 7969 pipe
init 1 root 4w FIFO 0,8 0t0 7969 pipe
init 1 root 5r DIR 0,10 0 1 inotify
init 1 root 6r DIR 0,10 0 1 inotify
init 1 root 7u unix 0xf61e3840 0t0 7970 socket
init 1 root 9u unix 0xf3bab280 0t0 11211 socket
在上面輸出的FD列中,顯示的是檔案的File Descriptor number,或者如下的内容:
cwd: current working directory;
mem: memory-mapped file;
mmap: memory-mapped device;
pd: parent directory;
rtd: root directory;
txt: program text (code and data);
檔案的File Descriptor number顯示模式有:
r for read access;
w for write access;
u for read and write access;
在上面輸出的TYPE列中,顯示的是檔案類型,如:
DIR: 目錄
LINK: 連結檔案
REG: 普通檔案
#檢視pid為1的程序(init)打開的檔案,其輸出結果等同于上面的指令,他們都是init。
/> lsof -p 1
#檢視owner為root的程序打開的檔案。
/> lsof -u root
#檢視owner不為root的程序打開的檔案。
/> lsof -u ^root
#檢視打開協定為tcp,ip為192.168.220.134,端口為22的程序。
/> lsof -i [email protected]:22
sshd 2829 root 3r IPv4 19635 0t0 TCP bogon:ssh->bogon:15264 (ESTABLISHED)
#檢視打開/root檔案夾,但不考慮目錄搜尋
/> lsof +d /root
#檢視打開/root檔案夾以及其子目錄搜尋
/> lsof +D /root
#檢視打開FD(0-3)檔案的所有程序
/> lsof -d 0-3
#-a選項會将+d選項和-c選項的選擇結果進行and操作,并輸出合并後的結果。
/> lsof +d .
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
bash 9707 root cwd DIR 8,1 4096 39887 .
lsof 9791 root cwd DIR 8,1 4096 39887 .
lsof 9792 root cwd DIR 8,1 4096 39887 .
/> lsof -a -c bash +d .
bash 9707 root cwd DIR 8,1 4096 39887 .
最後需要額外說明的是,如果在檔案名的末尾存在(delete),則說明該檔案已經被删除,隻是還存留在cache中。
4. 程序查找/殺掉指令(pgrep/pkill):
查找和殺死指定的程序, 他們的選項和參數完全相同, 這裡隻是介紹pgrep。下面是常用的指令行選項:
-d
定義多個程序之間的分隔符, 如果不定義則使用換行符。
-n
表示如果該程式有多個程序正在運作,則僅查找最新的,即最後啟動的。
-o
表示如果該程式有多個程序正在運作,則僅查找最老的,即最先啟動的。
-G
其後跟着一組group id,該指令在搜尋時,僅考慮group清單中的程序。
其後跟着一組有效使用者ID(effetive user id),該指令在搜尋時,僅考慮該effective user清單中的程序。
-U
其後跟着一組實際使用者ID(real user id),該指令在搜尋時,僅考慮該real user清單中的程序。
-x
表示程序的名字必須完全比對, 以上的選項均可以部分比對。
-l
将不僅列印pid,也列印程序名。
-f
一般與-l合用, 将列印程序的參數。
#手工建立兩個背景程序
/> sleep 1000&
3456
/> sleep 1000&
3457
#查找程序名為sleep的程序,同時輸出所有找到的pid
/> pgrep sleep
#查找程序名為sleep的程序pid,如果存在多個,他們之間使用:分隔,而不是換行符分隔。
/> pgrep -d: sleep
3456:3457
#查找程序名為sleep的程序pid,如果存在多個,這裡隻是輸出最後啟動的那一個。
/> pgrep -n sleep
#查找程序名為sleep的程序pid,如果存在多個,這裡隻是輸出最先啟動的那一個。
/> pgrep -o sleep
#查找程序名為sleep,同時這個正在運作的程序的組為root和stephen。
/> pgrep -G root,stephen sleep
#查找有效使用者ID為root和oracle,程序名為sleep的程序。
/> pgrep -u root,oracle sleep
#查找實際使用者ID為root和oracle,程序名為sleep的程序。
/> pgrep -U root,oracle sleep
#查找程序名為sleep的程序,注意這裡找到的程序名必須和參數中的完全比對。
/> pgrep -x sleep
#-x不支援部分比對,sleep程序将不會被查出,是以下面的指令沒有結果。
/> pgrep -x sle
#查找程序名為sleep的程序,同時輸出所有找到的pid和程序名。
/> pgrep -l sleep
3456 sleep
3457 sleep
#查找程序名為sleep的程序,同時輸出所有找到的pid、程序名和啟動時的參數。
/> pgrep -lf sleep
3456 sleep 1000
3457 sleep 1000
#查找程序名為sleep的程序,同時以逗号為分隔符輸出他們的pid,在将結果傳給ps指令,-f表示顯示完整格式,-p顯示pid清單,ps将隻是輸出該清單内的程序資料。
/> pgrep -f sleep -d, | xargs ps -fp
UID PID PPID C STIME TTY TIME CMD
root 3456 2138 0 06:11 pts/5 00:00:00 sleep 1000
root 3457 2138 0 06:11 pts/5 00:00:00 sleep 1000