【Linux入門教程】4 使用者管理、系統效能分析、系統日誌及日誌分析、訊號機制與訊號處理

HelloZEX發表於2018-08-03

Linux使用者管理

在Linux中,有三種使用者:

  • Root 使用者:也稱為超級使用者,對系統擁有完全的控制許可權。超級使用者可以不受限制的執行任何命令。Root 使用者可以看做是系統管理員。
  • 系統使用者:系統使用者是Linux執行某些程式所必須的使用者,例如 mail 使用者、sshd 使用者等。系統使用者通常為系統功能所必須的,不建議修改這些使用者。
  • 普通使用者:一般使用者都是普通使用者,這些使用者對系統檔案的訪問受限,不能執行全部Linux命令。


Linux支援使用者組,使用者組就是具有相同特徵的使用者的集合。一個組可以包含多個使用者,每個使用者也可以屬於不同的組。使用者組在Linux中扮演著重要的角色,方便管理員對使用者進行集中管理。

與使用者和組有關的系統檔案

與使用者和組有關的系統檔案:

系統檔案 說明
/etc/passwd 儲存使用者名稱和密碼等資訊,Linux系統中的每個使用者都在/etc/passwd檔案中有一個對應的記錄行。這個檔案對所有使用者都是可讀的。
/etc/shadow /etc/shadow中的記錄行和/etc/passwd中的相對應,他由pwconv命令根據/etc/passwd中的資料自動產生,它的格式和/etc/passwd類似,只是對密碼進行了加密。並不是所有的系統都支援這個檔案。
/etc/group 以記錄行的形式儲存了使用者組的所有資訊。


來看一下/etc/passwd檔案的結構:

$cat /etc/passwd
root:x:0:0:Superuser:/:
daemon:x:1:1:System daemons:/etc:
bin:x:2:2:Owner of system commands:/bin:
sys:x:3:3:Owner of system files:/usr/sys:
adm:x:4:4:System accounting:/usr/adm:
uucp:x:5:5:UUCP administrator:/usr/lib/uucp:
auth:x:7:21:Authentication administrator:/tcb/files/auth:
cron:x:9:16:Cron daemon:/usr/spool/cron:
listen:x:37:4:Network daemon:/usr/net/nls:
lp:x:71:18:printer administrator:/usr/spool/lp:
sam:x:200:50:Sam san:/usr/sam:/bin/sh

可以看到,/etc/passwd檔案中一行記錄對應著一個使用者,每行記錄又被冒號分隔為7個欄位,其格式和具體含義如下圖所示:


對每個欄位的說明:

欄位 說明
使用者名稱 使用者名稱是惟一的,長度根據不同的linux系統而定,一般是8位。
密碼 由於系統中還有一個/etc/shadow檔案用於存放加密後的口令,所以在這裡這一項是“x”來表示,如果使用者沒有設定口令,則該項為空。如果passwd欄位中的第一個字元是“*”的話,那麼,就表示該賬號被查封了,系統不允許持有該賬號的使用者登入。
使用者ID 系統內部根據使用者ID而不是使用者名稱來識別不同的使用者,使用者ID有以下幾種:
  • 0代表系統管理員,如果你想建立一個系統管理員的話,可以建立一個普通帳戶,然後將該賬戶的使用者ID改為0即可。
  • 1~500系統預留的ID。
  • 500以上是普通使用者使用。
組ID 其實這個和使用者ID差不多,用來管理群組,與/etc/group檔案相關。
描述資訊 這個欄位幾乎沒有什麼用,只是用來解釋這個賬號的意義。在不同的Linux系統中,這個欄位的 格式並沒有統一。在許多Linux系統中,這個欄位存放的是一段任意的註釋性描述文字,用做finger命令的輸出。
使用者主目錄 使用者登入系統的起始目錄。使用者登入系統後將首先進入該目錄。root使用者預設是/,普通使用者是/home/username。
使用者Shell 使用者登入系統時使用的Shell。

管理使用者和組

下面是一些常用的管理使用者和組的命令:

命令 說明
useradd 新增使用者。
usermod 修改使用者資訊。
userdel 刪除使用者。
groupadd 新增使用者組。
groupmod 修改使用者組資訊。
groupdel 刪除使用者組。

建立使用者組

新增使用者時,可以將使用者新增到現有的使用者組,或者建立一個新的使用者組。可以在 /etc/groups 檔案中看到所有的使用者組資訊。

預設的使用者組通常用來管理系統使用者,不建議將普通使用者新增到這些使用者組。使用groupadd命令建立使用者組的語法為:

groupadd [-g gid [-o]] [-r] [-f] groupname

每個選項的含義如下:

選項 說明
-g GID 以數字表示的使用者組ID。
-o 可以使用重複的組ID。
-r 建立系統組,用來管理系統使用者。
-f 強制建立。
groupname 使用者組的名稱。


如果不指定選項,系統將使用預設值。例如建立一個 developers 使用者組:

$ groupadd developers

修改使用者組

groupmod命令可以用來修改使用者組,語法為:

$ groupmod -n new_modified_group_name old_group_name

例如,將使用者組 developers_2 重新命名為 developer:

$ groupmod -n developer developer_2

將developer使用者組的ID改為545:

$ groupmod -g 545 developer

刪除使用者組

通過groupdel命令可以刪除使用者組。例如,刪除developer組:

$ groupdel developer

groupdel 僅僅刪除使用者組,並不刪除與之相關的檔案,這些檔案仍然可以被所有者訪問。

新增使用者

新增使用者可以使用useradd命令,語法為:

useradd -d homedir -g groupname -m -s shell -u userid accountname

每個選項的含義如下:

選項 描述
-d homedir 指定使用者主目錄。
-g groupname 指定使用者組。
-m 如果主目錄不存在,就建立。
-s shell 為使用者指定預設Shell。
-u userid 指定使用者ID。
accountname 使用者名稱。


如果不指定任何選項,系統將使用預設值。useradd 命令將會修改 /etc/passwd、/etc/shadow、and /etc/group 三個檔案,並建立使用者主目錄。

下面的例子將會新增使用者 mcmohd,並設定主目錄為 /home/mcmohd,使用者組為 developers,預設 Shell 為  Korn Shell:

$ useradd -d /home/mcmohd -g developers -s /bin/ksh mcmohd

注意:新增使用者前請確認 developers 使用者組存在。

使用者被建立後,可以使用 passwd 命令來設定密碼,例如:

$ passwd mcmohd20
Changing password for user mcmohd20.
New Linux password:******
Retype new UNIX password:******
passwd: all authentication tokens updated successfully.

注意:如果你是管理員,輸入 $ passwd username 可以修改你所管理的使用者的密碼;否則只能修改你自己的密碼(不需要提供username)。

修改使用者

usermod 命令可以修改現有使用者的資訊。usermod 命令的選項和 useradd 相同,不過可以增加 -l 選項來更改使用者名稱。

下面的例子將使用者 mcmohd 的使用者名稱修改為 mcmohd20,主目錄修改為 /home/mcmohd20:

$ usermod -d /home/mcmohd20 -m -l mcmohd mcmohd20

刪除使用者

userdel 命令可以用來刪除現有使用者。userdel 是一個危險的命令,請謹慎使用。

userdel 命令僅有一個選項 -r,用來刪除使用者主目錄和本地郵件。例如,刪除使用者  mcmohd20:

$ userdel -r mcmohd20

為了便於恢復被誤刪的使用者,可以忽略 -r 選項,保留使用者主目錄,之後確認無誤可以隨時刪除主目錄。



Linux系統效能分析

這篇教程的目的是向大家介紹一些免費的系統效能分析工具(命令),使用這些工具可以監控系統資源使用情況,便於發現效能瓶頸。

系統的整體效能取決於各種資源的平衡,類似木桶理論,某種資源的耗盡會嚴重阻礙系統的效能。


Linux中需要監控的資源主要有 CPU、主存(記憶體)、硬碟空間、I/O時間、網路時間、應用程式等。

影響系統效能的主要因素有:

因素 說明
使用者態CPU CPU在使用者態執行使用者程式所花費的時間,包括庫呼叫,但是不包括核心花費的時間。
核心態CPU CPU在核心態執行系統服務所花費的時間。所有的 I/O 操作都需要呼叫系統服務,程式設計師可以通過阻塞 I/O 傳輸來影響這部分的時間。
I/O 時間和網路時間 響應 I/O 請求、處理網路連線所花費的時間。
記憶體 切換上下文和交換資料(虛擬記憶體頁匯入和匯出)花費的時間。
應用程式 程式等待執行的時間——CPU正在執行其他程式,等待切換到當前程式。


說明:一般認為使用者態CPU和核心態CPU花費的時間小於70%時是良好狀態。

下面的命令可以用來監控系統效能並作出相應調整:

命令 說明
nice 啟動程式時指定程式優先順序。
renice 調整現有程式的優先順序。
netstat 顯示各種網路相關資訊,包括網路連線情況、路由表、介面狀態(Interface Statistics)、masquerade 連線、多播成員 (Multicast Memberships)等。實際上,netstat 用於顯示與IP、TCP、UDP和ICMP協議相關的統計資料,一般用於檢驗本機各埠的網路連線情況。
time 檢測一個命令執行時間以及資源(CPU、記憶體、I/O等)使用情況。
uptime 檢視系統負載情況。
ps 檢視系統中程式的資源使用情況(瞬時狀態,不是動態監控)。
vmstat 報告虛擬記憶體使用情況。
gprof 精確分析程式的效能,能給出函式呼叫時間、呼叫次數、呼叫關係等。
top 實時監控系統中各個程式資源的資源使用情況。


常用命令組合:

  • vmstat、sar、mpstat檢測是否存在CPU瓶頸;
  • vmstat、free檢測是否存在記憶體瓶頸;
  • iostat檢測是否存在磁碟I/O瓶頸;
  • netstat檢測是否存在網路I/O瓶頸。


Linux系統日誌及日誌分析

Linux系統擁有非常靈活和強大的日誌功能,可以儲存幾乎所有的操作記錄,並可以從中檢索出我們需要的資訊。

大部分Linux發行版預設的日誌守護程式為 syslog,位於 /etc/syslog 或 /etc/syslogd,預設配置檔案為 /etc/syslog.conf,任何希望生成日誌的程式都可以向 syslog 傳送資訊。 

Linux系統核心和許多程式會產生各種錯誤資訊、警告資訊和其他的提示資訊,這些資訊對管理員瞭解系統的執行狀態是非常有用的,所以應該把它們寫到日誌檔案中去。完成這個過程的程式就是syslog。syslog可以根據日誌的類別和優先順序將日誌儲存到不同的檔案中。例如,為了方便查閱,可以把核心資訊與其他資訊分開,單獨儲存到一個獨立的日誌檔案中。預設配置下,日誌檔案通常都儲存在“/var/log”目錄下。

日誌型別

下面是常見的日誌型別,但並不是所有的Linux發行版都包含這些型別:

型別 說明
auth 使用者認證時產生的日誌,如login命令、su命令。
authpriv 與 auth 類似,但是隻能被特定使用者檢視。
console 針對系統控制檯的訊息。
cron 系統定期執行計劃任務時產生的日誌。
daemon 某些守護程式產生的日誌。
ftp FTP服務。
kern 系統核心訊息。
local0.local7 由自定義程式使用。
lpr 與印表機活動有關。
mail 郵件日誌。
mark 產生時間戳。系統每隔一段時間向日志檔案中輸出當前時間,每行的格式類似於 May 26 11:17:09 rs2 -- MARK --,可以由此推斷系統發生故障的大概時間。
news 網路新聞傳輸協議(nntp)產生的訊息。
ntp 網路時間協議(ntp)產生的訊息。
user 使用者程式。
uucp UUCP子系統。

日誌優先順序

常見的日誌優先順序請見下標:

優先順序 說明
emerg 緊急情況,系統不可用(例如系統崩潰),一般會通知所有使用者。
alert 需要立即修復,例如系統資料庫損壞。
crit 危險情況,例如硬碟錯誤,可能會阻礙程式的部分功能。
err 一般錯誤訊息。
warning 警告。
notice 不是錯誤,但是可能需要處理。
info 通用性訊息,一般用來提供有用資訊。
debug 除錯程式產生的資訊。
none 沒有優先順序,不記錄任何日誌訊息。

常見日誌檔案

所有的系統應用都會在 /var/log 目錄下建立日誌檔案,或建立子目錄再建立日誌檔案。例如:

檔案/目錄 說明
/var/log/boot.log 開啟或重啟日誌。
/var/log/cron 計劃任務日誌
/var/log/maillog 郵件日誌。
/var/log/messages 該日誌檔案是許多程式日誌檔案的彙總,從該檔案可以看出任何入侵企圖或成功的入侵。
/var/log/httpd 目錄 Apache HTTP 服務日誌。
/var/log/samba 目錄 samba 軟體日誌

 

/etc/syslog.conf 檔案

/etc/syslog.conf 是 syslog 的配置檔案,會根據日誌型別和優先順序來決定將日誌儲存到何處。典型的 syslog.conf 檔案格式如下所示:

*.err;kern.debug;auth.notice /dev/console
daemon,auth.notice           /var/log/messages
lpr.info                     /var/log/lpr.log
mail.*                       /var/log/mail.log
ftp.*                        /var/log/ftp.log
auth.*                       @see.xidian.edu.cn
auth.*                       root,amrood
netinfo.err                  /var/log/netinfo.log
install.*                    /var/log/install.log
*.emerg                      *
*.alert                      |program_name
mark.*                       /dev/console

第一列為日誌型別和日誌優先順序的組合,每個型別和優先順序的組合稱為一個選擇器;後面一列為儲存日誌的檔案、伺服器,或輸出日誌的終端。syslog 程式根據選擇器決定如何操作日誌。

對配置檔案的幾點說明:

  • 日誌型別和優先順序由點號(.)分開,例如 kern.debug 表示由核心產生的除錯資訊。
  • kern.debug 的優先順序大於 debug。
  • 星號(*)表示所有,例如 *.debug 表示所有型別的除錯資訊,kern.* 表示由核心產生的所有訊息。
  • 可以使用逗號(,)分隔多個日誌型別,使用分號(;)分隔多個選擇器。


對日誌的操作包括:

  • 將日誌輸出到檔案,例如 /var/log/maillog 或 /dev/console。
  • 將訊息傳送給使用者,多個使用者用逗號(,)分隔,例如 root, amrood。
  • 通過管道將訊息傳送給使用者程式,注意程式要放在管道符(|)後面。
  • 將訊息傳送給其他主機上的 syslog 程式,這時 /etc/syslog.conf 檔案後面一列為以@開頭的主機名,例如@see.xidian.edu.cn。

logger 命令

logger 是Shell命令,可以通過該命令使用 syslog 的系統日誌模組,還可以從命令列直接向系統日誌檔案寫入一行資訊。

logger命令的語法為:

logger [-i] [-f filename] [-p priority] [-t tag] [message...]

每個選項的含義如下:

選項 說明
-f filename 將 filename 檔案的內容作為日誌。
-i 每行都記錄 logger 程式的ID。
-p priority 指定優先順序;優先順序必須是形如 facility.priority 的完整的選擇器,預設優先順序為 user.notice。
-t tag 使用指定的標籤標記每一個記錄行。
message 要寫入的日誌內容,多條日誌以空格為分隔;如果沒有指定日誌內容,並且 -f filename 選項為空,那麼會把標準輸入作為日誌內容。


例如,將ping命令的結果寫入日誌:

$ ping 192.168.0.1 | logger -it logger_test -p local3.notice&
$ tail -f /var/log/userlog
Oct 6 12:48:43 kevein logger_test[22484]: PING 192.168.0.1 (192.168.0.1) 56(84) bytes of data.
Oct 6 12:48:43 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=1 ttl=253 time=49.7 ms
Oct 6 12:48:44 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=2 ttl=253 time=68.4 ms
Oct 6 12:48:45 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=3 ttl=253 time=315 ms
Oct 6 12:48:46 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=4 ttl=253 time=279 ms
Oct 6 12:48:47 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=5 ttl=253 time=347 ms
Oct 6 12:48:49 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=6 ttl=253 time=701 ms
Oct 6 12:48:50 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=7 ttl=253 time=591 ms
Oct 6 12:48:51 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=8 ttl=253 time=592 ms
Oct 6 12:48:52 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=9 ttl=253 time=611 ms
Oct 6 12:48:53 kevein logger_test[22484]: 64 bytes from 192.168.0.1: icmp_seq=10 ttl=253 time=931 ms

ping命令的結果成功輸出到 /var/log/userlog 檔案。

命令 logger -it logger_test -p local3.notice 各選項的含義:

  • -i:在每行都記錄程式ID;
  • -t logger_test:每行記錄都加上“logger_test”這個標籤;
  • -p local3.notice:設定日誌型別和優先順序。

日誌轉儲

日誌轉儲也叫日誌回捲或日誌輪轉。Linux中的日誌通常增長很快,會佔用大量硬碟空間,需要在日誌檔案達到指定大小時分開儲存。

syslog 只負責接收日誌並儲存到相應的檔案,但不會對日誌檔案進行管理,因此經常會造成日誌檔案過大,尤其是WEB伺服器,輕易就能超過1G,給檢索帶來困難。

大多數Linux發行版使用 logrotate 或 newsyslog 對日誌進行管理。logrotate 程式不但可以壓縮日誌檔案,減少儲存空間,還可以將日誌傳送到指定 E-mail,方便管理員及時檢視日誌。

例如,規定郵件日誌 /var/log/maillog 超過1G時轉儲,每週一次,那麼每隔一週 logrotate 程式就會檢查 /var/log/maillog 檔案的大小:

  • 如果沒有超過1G,不進行任何操作。
  • 如果在1G~2G之間,就會建立新檔案 /var/log/maillog.1,並將多出的1G日誌轉移到該檔案,以給 /var/log/maillog 檔案瘦身。
  • 如果在2G~3G之間,會繼續建立新檔案 /var/log/maillog.2,並將 /var/log/maillog.1 的內容轉移到該檔案,將 /var/log/maillog 的內容轉移到 /var/log/maillog.1,以保持 /var/log/maillog 檔案不超過1G。


可以看到,每次轉存都會建立一個新檔案(如果不存在),命名格式為日誌檔名加一個數字(從1開始自動增長),以保持當前日誌檔案和轉存後的日誌檔案不超過指定大小。

logrotate 的主要配置檔案是 /etc/logrotate.conf,/etc/logrotate.d 目錄是對 /etc/logrotate.conf 的補充,或者說為了不使 /etc/logrotate.conf 過大而設定。

可以通過 cat 命令檢視它的內容:

$cat /etc/logrotate.conf
# see "man logrotate" for details  //可以檢視幫助文件
# rotate log files weekly
weekly                             //設定每週轉儲一次
# keep 4 weeks worth of backlogs
rotate 4                           //最多轉儲4次
# create new (empty) log files after rotating old ones
create                             //當轉儲後檔案不儲存時建立它
# uncomment this if you want your log files compressed
#compress                          //以壓縮方式轉儲
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d           //其他日誌檔案的轉儲方式,包含在該目錄下
# no packages own wtmp -- we'll rotate them here
/var/log/wtmp {                    //設定/var/log/wtmp日誌檔案的轉儲引數
    monthly                        //每月轉儲
    create 0664 root utmp          //轉儲後檔案不存在時建立它,檔案所有者為root,所屬組為utmp,對應的許可權為0664
    rotate 1                       //最多轉儲一次
}


注意:include 允許管理員把多個分散的檔案集中到一個,類似於C語言的 #include,將其他檔案的內容包含進當前檔案。

include 非常有用,一些程式會把轉儲日誌的配置檔案放在 /etc/logrotate.d 目錄,這些配置檔案會覆蓋或增加 /etc/logrotate.conf 的配置項,如果沒有指定相關配置,那麼採用 /etc/logrotate.conf 的預設配置。

所以,建議將 /etc/logrotate.conf 作為預設配置檔案,第三方程式在 /etc/logrotate.d 目錄下自定義配置檔案。

logrotate 也可以作為命令直接執行來修改配置檔案。

 



Linux訊號機制與訊號處理

訊號(signal)是Linux程式間通訊的一種機制,全稱為軟中斷訊號,也被稱為軟中斷。訊號本質上是在軟體層次上對硬體中斷機制的一種模擬。

與其他程式間通訊方式(例如管道、共享記憶體等)相比,訊號所能傳遞的資訊比較粗糙,只是一個整數。但正是由於傳遞的資訊量少,訊號也便於管理和使用,可以用於系統管理相關的任務,例如通知程式終結、中止或者恢復等。

每種訊號用一個整型常量巨集表示,以SIG開頭,比如SIGCHLD、SIGINT等,它們在系統標頭檔案<signal.h>中定義。

訊號由核心(kernel)管理,產生方式多種多樣:

  • 可以由核心自身產生,比如出現硬體錯誤、記憶體讀取錯誤,分母為0的除法等,核心需要通知相應程式。
  • 也可以由其他程式產生併傳送給核心,再由核心傳遞給目標程式。


訊號傳遞的過程:

  • 核心中針對每一個程式都有一個表來儲存訊號。
  • 當核心需要將訊號傳遞給某個程式時,就在該程式對應的表中寫入訊號,這樣就生成了訊號。
  • 當該程式由使用者態陷入核心態,再次切換到使用者態之前,會檢視錶中的訊號。如果有訊號,程式就會首先執行訊號對應的操作,此時叫做執行訊號。
  • 從生成訊號到將訊號傳遞給對應程式這段時間,訊號處於等待狀態。
  • 我們可以編寫程式碼,讓程式阻塞(block)某些訊號,也就是讓這些訊號始終處於等待的狀態,直到程式取消阻塞(unblock)或者忽略訊號。

訊號種類

下表列出了一些常見訊號:

訊號名稱 數字表示 說明
SIGHUP 1 終端掛起或控制程式終止。當使用者退出Shell時,由該程式啟動的所有程式都會收到這個訊號,預設動作為終止程式。
SIGINT 2 鍵盤中斷。當使用者按下<Ctrl+C>組合鍵時,使用者終端向正在執行中的由該終端啟動的程式發出此訊號。預設動作為終止程式。 
SIGQUIT 3 鍵盤退出鍵被按下。當使用者按下<Ctrl+D>或<Ctrl+\>組合鍵時,使用者終端向正在執行中的由該終端啟動的程式發出此訊號。預設動作為退出程式。
SIGFPE 8 發生致命的運算錯誤時發出。不僅包括浮點運算錯誤,還包括溢位及除數為0等所有的演算法錯誤。預設動作為終止程式併產生core檔案。
SIGKILL 9 無條件終止程式。程式接收到該訊號會立即終止,不進行清理和暫存工作。該訊號不能被忽略、處理和阻塞,它向系統管理員提供了可以殺死任何程式的方法。
SIGALRM 14 定時器超時,預設動作為終止程式。
SIGTERM 15 程式結束訊號,可以由 kill 命令產生。與SIGKILL不同的是,SIGTERM 訊號可以被阻塞和終止,以便程式在退出前可以儲存工作或清理臨時檔案等。


通過 kill -l 命令可以檢視系統支援的所有訊號:

$ kill -l
1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU
25) SIGXFSZ     26) SIGVTALRM   27) SIGPROF     28) SIGWINCH
29) SIGIO       30) SIGPWR      31) SIGSYS      34) SIGRTMIN
35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3  38) SIGRTMIN+4
39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7  58) SIGRTMAX-6
59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

上面僅是一個演示,不同的Linux發行版支援的訊號可能不同。

每種訊號都會有一個預設動作。預設動作就是指令碼或程式接收到該訊號所做出的預設操作。常見的預設動作有終止程式、退出程式、忽略訊號、重啟暫停的程式等,上表中也對部分預設動作進行了說明。

傳送訊號

有多種方式可以向程式或指令碼傳送訊號,例如按下<Ctrl+C>組合鍵會傳送SIGINT訊號,終止當前程式。

還可以通過 kill 命令傳送訊號,語法為:

$ kill -signal pid

signal為要傳送的訊號,可以是訊號名稱或數字;pid為接收訊號的程式ID。例如:

$ kill -1 1001

將SIGHUP訊號傳送給程式ID為1001的程式,程式會終止執行。

又如,強制殺死ID為1001的程式:

$ kill -9 1001

捕獲訊號

通常情況下,直接終止程式並不是我們所希望的。例如,按下<Ctrl+C>,程式被立即終止,不會清理建立的臨時檔案,帶來系統垃圾,也不會儲存正在進行的工作,導致需要重做。

可以通過程式設計來捕獲這些訊號,當終止訊號出現時,可以先進行清場和儲存處理,再退出程式。

使用者程式可以通過C/C++等程式碼捕獲訊號,這將在Linux C程式設計中進行講解,這裡僅介紹如果通過Linux命令捕獲訊號。

通過 trap 命令就可以捕獲訊號,語法為:

$ trap commands signals

commands為Linux系統命令或使用者自定義命令;signals為要捕獲的訊號,可以為訊號名稱或數字。

捕獲到訊號後,可以有三種處理:

  • 執行一段指令碼來做一些處理工作,例如清理臨時檔案;
  • 接受(恢復)訊號的預設操作;
  • 忽略當前訊號。

1) 清理臨時檔案

指令碼捕獲到終止訊號後一個常見的動作就是清理臨時檔案。例如:

$ trap "rm -f $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 2

當使用者按下<Ctrl+C>後,指令碼先清理臨時檔案 work1$$ 和 dataout$$ 再退出。

注意:exit 命令是必須的,否則指令碼捕獲到訊號後會繼續執行而不是退出。

修改上面的指令碼,使接收到 SIGHUP 時進行同樣的操作:

$ trap "rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit" 1 2

幾點注意:

  • 如果執行多個命令,需要將命令用引號包圍;
  • 只有指令碼執行到 trap 命令時才會捕獲訊號;
  • 再次接收到訊號時還會執行同樣的操作。


上面的指令碼,執行到 trap 命令時就會替換 WORKDIR 和 $$ 的值。如果希望接收到 SIGHUP 或 SIGINT 訊號時再替換其值,那麼可以將命令放在單引號內,例如:

$ trap 'rm $WORKDIR/work1$$ $WORKDIR/dataout$$; exit' 1 2

2) 忽略訊號

如果 trap 命令的 commands 為空,將會忽略接收到的訊號,即不做任何處理,也不執行預設動作。例如:

$ trap '' 2

也可以同時忽略多個訊號:

$ trap '' 1 2 3 15

注意:必須被引號包圍,不能寫成下面的形式:

$ trap  2

3) 恢復預設動作

如果希望改變訊號的預設動作後再次恢復預設動作,那麼省略 trap 命令的 commands 即可,例如:

$ trap 1 2

將恢復SIGHUP 和 SIGINT 訊號的預設動作。

相關文章