pgrep 指令:依名稱找 PID、-f 選項,以及 pidof 與 pkill 的差異

測試環境RHEL 系列AlmaLinux 9.8procps-ng 3.3root 帳號Debian 12 · procps-ng 4.0.2 一般帳號
程序 · 工作排程指令pgrep, pidof位置/usr/bin/pgrep

要依名稱、帳號或命令列找出執行中程序的編號(PID),就使用 pgrep 指令。我們在 AlmaLinux 9 伺服器上把 sleep 程式複製成其他名稱,啟動三個程序,再比較各選項找到的程序。依名稱找只出現這三個程序,用 -f 在整個命令列中找時,連啟動它們的 timeout 也一起出現。

下方輸出是在 AlmaLinux 9.8 伺服器的 root 帳號與 Debian 12 伺服器的一般帳號上執行的結果。要找的對象是把 sleep 複製成 pgdemo-a、pgdemo-b 這兩個名稱,再用 timeout 300 啟動的程序,讓它們 5 分鐘後自行結束。程序編號(PID)和 Debian 帳號名稱(user1)已換成範例值,AlmaLinux 伺服器的 procps-ng 版本號只寫到主版本與次版本。

1️⃣ pgrep 指令基本用法

  • ↪️ 依名稱找 PID 與結束代碼

在 pgrep 後面寫上名稱的一部分,就會把名稱含有這些字元的程序編號一行一個輸出。用 pgdemo 找時出現了兩個 pgdemo-a 和一個 pgdemo-b,共三個編號。

pgrep pgdemo
2143
2152
2155

把名稱寫到 pgdemo-a 時,只剩下兩個 pgdemo-a。

pgrep pgdemo-a
2143
2152

要找的字串以延伸正規表示式讀取,沒有選項時只在程序名稱中找。

找不到符合的程序時不會輸出任何東西就結束,所以要用結束代碼確認結果。找了不存在的名稱 pgdemo-zz 後執行 [echo $?],得到 1。

pgrep pgdemo-zz
echo $?
1

不寫任何條件就執行時,出現下方錯誤和結束代碼 2。man 頁面把結束代碼說明為 0(找到)、1(找不到)、2(命令列語法錯誤)、3(記憶體不足等嚴重錯誤)。

pgrep
pgrep: no matching criteria specified
Try `pgrep --help' for more information.
echo $?
2

把這個結束代碼當作條件而不是看輸出,腳本就能確認程序是否在執行。版本用 [pgrep -V] 確認。Debian 12 伺服器是 procps-ng 4.0.2,AlmaLinux 9.8 伺服器是 procps-ng 3.3。

pgrep -V
pgrep from procps-ng 4.0.2

2️⃣ pgrep -f 選項與 -l、-a 輸出

  • ↪️ 在整個命令列中找時一起出現的程序

只看編號無法知道是哪個程序,所以用 -l 一起輸出名稱,用 -a 一起輸出整個命令列。

pgrep -l pgdemo
2143 pgdemo-a
2152 pgdemo-a
2155 pgdemo-b
pgrep -a pgdemo
2143 ./pgdemo-a 300
2152 ./pgdemo-a 301
2155 ./pgdemo-b 300

-a 輸出最後的 300 和 301 是傳給 sleep 的秒數引數。我們用這個引數區分了兩個同名的 pgdemo-a。

加上 -f 就不是在名稱中找,而是在整個命令列中找。用 -f 找 pgdemo-a 時,編號從兩個增加到四個。

pgrep -f pgdemo-a
2141
2143
2150
2152

再加上 -a 一看,多出來的兩行是以 pgdemo-a 為引數執行的 timeout。它們的名稱是 timeout,但命令列中含有 pgdemo-a,所以符合 -f 的條件。

pgrep -af pgdemo-a
2141 timeout 300 ./pgdemo-a 300
2143 ./pgdemo-a 300
2150 timeout 300 ./pgdemo-a 301
2152 ./pgdemo-a 301

在腳本中使用 -f 時,要確認腳本本身會不會出現在結果中。pgrep 不會把執行中的自己放進結果,但如果執行 pgrep 的腳本命令列中有要找的字串,那個腳本也會出現在結果中。

用把收到的字串直接交給 [pgrep -af] 的腳本 chk.sh 找 pgdemo-a 時,最後一行多了腳本本身 bash chk.sh pgdemo-a。

bash chk.sh pgdemo-a
2141 timeout 300 ./pgdemo-a 300
2143 ./pgdemo-a 300
2150 timeout 300 ./pgdemo-a 301
2152 ./pgdemo-a 301
2160 bash chk.sh pgdemo-a

用方括號把第一個字母括起來的 [p]gdemo-a,以正規表示式來說會找和 pgdemo-a 相同的字串,但腳本命令列中連方括號都原樣寫著,所以不符合條件。把這個模式交給同一個腳本後,腳本那一行消失,只剩四行。

bash chk.sh '[p]gdemo-a'
2141 timeout 300 ./pgdemo-a 300
2143 ./pgdemo-a 300
2150 timeout 300 ./pgdemo-a 301
2152 ./pgdemo-a 301

3️⃣ pgrep 條件選項

  • ↪️ -u 帳號、-x 完整名稱、-n 與 -o、-c 個數

加上 -x 就只找名稱完全相同的程序,而不是名稱的一部分。用 pgdemo 什麼都沒找到,用 pgdemo-a 找到兩個。

pgrep -x pgdemo
pgrep -lx pgdemo-a
2143 pgdemo-a
2152 pgdemo-a

-u 依執行程序的帳號篩選。用逗號寫多個帳號時,會找出屬於其中任一帳號的所有程序。以 root 執行的三個程序用 [-u root] 全部出現,用 [-u daemon] 一個也沒有。

pgrep -u root -l pgdemo
2143 pgdemo-a
2152 pgdemo-a
2155 pgdemo-b
pgrep -u daemon -l pgdemo
pgrep -u root,daemon -c pgdemo
3

寫了不存在的帳號時,出現 [invalid user name] 錯誤和結束代碼 2。

pgrep -u no-such-user9 pgdemo
pgrep: invalid user name: no-such-user9

在 Debian 12 伺服器的一般帳號上,也用相同選項找到了以自己帳號啟動的一個 sleep。

pgrep -u user1 -l sleep
3047 sleep
pgrep -u user1 -a sleep
3047 sleep 60

同名的程序有多個時,-n 只輸出最近啟動的一個,-o 只輸出最早啟動的一個。在間隔 2 秒啟動的兩個 pgdemo-a 中,-n 選了後啟動的,-o 選了先啟動的。

pgrep -n pgdemo-a
2152
pgrep -o pgdemo-a
2143

man 頁面說明 -n 和 -o 不能同時使用。兩個一起寫時,沒有錯誤訊息,只出現用法說明。

-c 輸出個數而不是編號。找不到時輸出 0,結束代碼是 1。

pgrep -c pgdemo
3
pgrep -c pgdemo-zz
0

pgrep 選項整理如下。

選項複製說明
-f--full不在名稱而在整個命令列中找
-l--list-name編號連同名稱一起輸出
-a--list-full編號連同整個命令列一起輸出
-x--exact只找名稱完全相同的程序
-u--euid只找指定帳號執行的程序,用逗號寫多個時為其中任一帳號
-n--newest符合條件中最近啟動的一個
-o--oldest符合條件中最早啟動的一個
-c--count輸出個數而不是編號,0 個時結束代碼為 1
-d--delimiter指定編號之間的分隔字元(預設為換行)
-V--version輸出版本
選項複製說明
-i--ignore-case不分大小寫地找
-v--inverse找出不符合條件的程序
-P--parent只找指定父程序編號(PPID)的子程序
-t--terminal只找連接到指定終端機的程序
-g--pgroup只找屬於指定程序群組編號的程序
-s--session只找屬於指定工作階段編號的程序
-U--uid只找真實使用者 ID 相同的程序
-G--group只找真實群組 ID 相同的程序
-w--lightweight輸出所有執行緒編號而不是程序編號

🔲 pgrep 指令模擬器

下方模擬器從 pgdemo 與 timeout 六行再加上範例程序的清單開始。點選按鈕可在左側清單比較各選項找到的行,也能在 [pkill pgdemo-b] 之後用 [pgrep -l pgdemo] 確認結果變少。

pgrep 指令模擬器procps-ng 3.3
[root@server work]#
只在瀏覽器中運作。左側清單是範例值,pgrep 找到的行旁邊會加上 [Just matched]。[pkill] 只是從清單中刪除的模擬。

4️⃣ pgrep 與 pidof、pkill 的差異

  • ↪️ 照名稱尋找的 pidof 與送出訊號的 pkill

pidof 不用正規表示式,只找程式名稱完全相同的程序,並把編號以空格隔開輸出在同一行。找 pgdemo-a 時兩個編號出現在同一行,後啟動的 2152 排在前面。

pidof pgdemo-a
2152 2143

用名稱的一部分 pgdemo 時,和 pgrep 不同,什麼都沒找到,結束代碼是 1。只需要一個編號時加上 -s。[pidof -s pgdemo-a] 只輸出了 2152。

pidof pgdemo
pidof -s pgdemo-a
2152

若要用找到的編號查看啟動時間與父程序編號(PPID),就用 pgrep -d 以逗號串起編號,再交給 ps 指令的 -p。

pgrep -d, pgdemo
2143,2152,2155
ps -fp $(pgrep -d, -x pgdemo-a)
UID          PID    PPID  C STIME TTY          TIME CMD
root        2143    2141  0 15:59 ?        00:00:00 ./pgdemo-a 300
root        2152    2150  0 15:59 ?        00:00:00 ./pgdemo-a 301

PPID 欄的 2141 和 2150 是執行兩個 pgdemo-a 的 timeout 的編號。

pkill 用與 pgrep 相同的條件找程序,但不輸出編號,而是送出訊號。不寫訊號時送出 SIGTERM,也可以像 [pkill -HUP 名稱] 這樣換成其他訊號。

pkill 一找到就立刻送出訊號,所以要先用相同條件的 [pgrep -a] 或 [pgrep -af] 確認對象。用 -f 找時,命令列中含有相同字串的 timeout 或腳本也會成為對象。如果已經知道編號,就用 kill 指令只對該編號送出訊號。

指令尋找依據輸出作用
pgrep名稱的一部分(正規表示式)、-f 時為整個命令列編號,用 -l、-a 加上名稱與命令列只找
pidof完整的程式名稱編號寫在同一行只找
pkill與 pgrep 相同的條件無對找到的程序送出訊號(預設 SIGTERM)

🔢 FAQ & 推薦內容

pgrep 只比較 /proc/PID/stat 中留下的程序名稱前 15 個字元。名稱超過 15 個字元時,用前 15 個字元找,或用 -f 在 /proc/PID/cmdline 的整個命令列中找。

用 grep 篩選 ps 清單時,那個 grep 的命令列中也含有要找的名稱,所以可能一起出現在結果中。pgrep 不會把執行中的自己放進結果,而且只輸出編號,方便交給其他指令。

加上 -v 就會反轉條件,找出不符合的程序。pkill 為了防止誤操作,不能使用短選項 -v。

ℹ️ 聯盟行銷說明
本站內容包含聯盟行銷連結。訪客透過這些連結購買商品或服務時,本站會從賣家獲得佣金。在這個過程中,購買者支付的金額(遇到活動折扣時金額會降低↓)並不會因此提高。刊登的價格、折扣與庫存資訊以撰寫當時為準,可能與實際情況不同,購買前請向賣家做最後確認。商品的挑選與評價依本站自訂的標準撰寫,是否支付佣金不會影響介紹順序或評價內容。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Prove your humanity: 10   +   5   =