探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

Overview of Content

Linux 訊號是作業系統中用於通信的關鍵機制之一,本篇將帶您深入了解 Bash 腳本中的訊號處理、信號的產生、捕捉以及改變捕捉後的行為。同時,您還將學會如何在後台運行腳本以及有效管理後台進程,包括查看、暫停和恢復作業。此外,我們將探討如何調整進程的謙讓度,以及安排定期執行腳本的各種方法,包括使用 cron 和 at 命令,以及補足 cron 缺失的 anacron 命令。

啟動腳本的方式除了直接呼叫控制之外,還可以透過向腳本發送訊號來控制腳本

寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀

個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看


認識 Linux 訊號

Linux 系統 & 應用程式可以產生很多信號,以下列出幾個我們最常見的信號

信號對應值說明
1SIGHUP掛起(Hang up)
2SIGINT中斷(interrupt)
3SIGQUIT停止
9SIGKILL無條件終止
15SIGTERM盡可能地終止
17SIGSTOP無條件停止(不等於終止)
18SIGCON繼續停止的進程
19SIGTSTP暫停

# 查看所有信號

man 7 signal

Bash 處理信號

● 信號會傳遞到腳本中讓腳本去處理,而 Bash Shell 對於信號的處理有以下特性

● 默認情況下 Bash Shell 會處理 SIGHUP(1)、SIGINT(2)信號,但忽略 SIGQUIT(3)、SIGTERM(15)信號

● 如果 Shell 收到信號,那它會 傳遞到每個 Sub Shell (Child Shell) 中

產生信號:快捷鍵 & 指令

● 使用 快捷鍵 產生訊號

A. 中斷Ctrl + C 產生 SIGINT(2)信號

測試如下:使用按鍵中斷 sleep 命令


sleep 100

B. 暫停Ctrl + Z 產生 SIGTSTP(18)信號;暫停進程與停止進程不同,暫停進程代表該進程仍在記憶體中,隨時可恢復

測試如下:使用按鍵暫停 sleep 命令


sleep 100

暫停進程後,Linux 會分配一個作業好 (job number) 給暫停的進程

可以透過 ps f 命令查看 STAT 欄位,來觀察進程的狀態

可以看到上圖 進程 STAT 為 T,這代表進程(執行命令的進程)被停止

● 使用 指令 產生訊號:

使用 kill 命令,並指定要產生的信號,就可以對進程發送指定信號;格式如下


kill [options] <PID>

可以透過 -l 查看 kill 可發送的訊號

● 範例:透過 kill 對指定進程(透過 PID)發送指定信號


# 對進程 99882
# 發送 SIGKILL 信號

kill -9 99882

捕捉信號 trap

● 我們知道每個腳本都預設可以接收訊號;我們也可以 透過 trap 命令主動去指定我們要捕捉某個訊號trap 格式如下:


trap <命令> 指定訊號

捕捉到指定訊號後,執行 命令 的內容

Trap 捕捉信號範例

捕捉但不處理,以下捕捉 SIGINT 訊號(使用 Ctrl-C 來產生這個訊號)


#!/bin/bash

trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT

count=1

while [ $count -le 10 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

捕捉腳本退出信號

在腳本完成並準備退出時會發出一個 EXIT 訊號

而我們也可以 透過 trap 命令捕捉腳本退出的時機(也就是腳本退出時發生的信號)… 範例如下:


#!/bin/bash

trap "echo 'The script finish'" EXIT

count=1

while [ $count -le 10 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

這裡的 trap 捕捉的信號是退出的信號,如果想改成 捕捉到某個信號才退出,那我們可以這樣修改如下

在補捉到信號時,去執行 exit 命令


#!/bin/bash

trap "echo 'The script get SIGSTP~'; exit" SIGSTP

count=1

while [ $count -le 10 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

改變捕捉後的行為

● 如果要改變捕捉信號的行為,只需要「再寫一次 trap 命令」 並依照需求修改為需要執行的命令,這樣就會產生「後蓋前」的行為(後面的 trap 命令覆蓋前面的 trap 命令)

使用範例如下:


#!/bin/bash

trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT

count=1

while [ $count -le 5 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

# 跳出循環時,再次覆蓋捕捉 SIGINT
trap "echo 'I modify trapped~~'; whoami" SIGINT

count=1

while [ $count -le 5 ] ; do
    echo "~~ Second times: $count"

    sleep 1

    (( count++ ))
done

● 這裡要注意,要捕捉同一個信號才可以覆蓋

移除捕捉到的信號

● 將 trap 命令,轉換為「單破折號(-)」或是「雙破折號(--)」就可以取消捕捉;

格式如下,兩種方式都可以,擇一即可


trap - 指定信號

trap -- 指定信號

移除 trap 信號的範例:


#!/bin/bash

trap "echo 'Sorry! I have trapped Ctrl-C'" SIGINT

count=1

while [ $count -le 5 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

# 移除信號
trap -- SIGINT

count=1

while [ $count -le 5 ] ; do
    echo "~~ Second times: $count"

    sleep 1

    (( count++ ))
done

後台進程與腳本

腳本在後台(background)模式中就不會影響前台,前台可以繼續作業

腳本後台運行:JobIndex

● 要讓腳本運行在後台很簡單,只需要在呼叫腳本時,在腳本後添加 & 符號即可;格式如下


運行腳本 &

腳本後台運行範例


#!/bin/bash

count=1

while [ $count -le 10 ] ; do
    echo "Test times: $count"

    sleep 1

    (( count++ ))
done

● 腳本在後台運行時仍會使用 STDOUTSTDERR,如果你沒有重新指向的話,它就會輸出在螢幕上

● 在規定腳本後台運行後,會 返回一組號碼,那組號碼就是後台運行的 JobIndex & PID

Job 概念後面會提及

在終端啟動的腳本後台腳本會與當前終端產生關聯,如果終端關閉了,那該終端啟動的後台進程也會關閉(下個小節會說一個脫離終端的方式)

腳本脫離終端關聯:nohup

● 前面有提到,腳本預設會與啟動它的終端有聯繫,如果終端關閉,該腳本就算沒運行完畢也會被關閉;以下範例,我們啟動一個腳本,關閉視窗(中斷)

A. 撰寫測試腳本:該腳本重新定向輸出到 relate_termial 檔案


#!/bin/bash

count=1

while [ $count -le 10 ] ; do

    echo "Hello, relate with termial: $count"

    sleep 1

    (( count++ ))
done

B. 背景啟動以下腳本


./normal_output.sh &

C. 快速關閉啟動腳本的終端(按下叉叉),輸出自然被中斷

Linux 有提供一個 nohup 命令,可以 1.切斷腳本 & 啟動它的終端的關聯,如果有輸出結果 2. 將結果輸出到 nohup.out 文件中

如果在同級目錄中多個 nohup 命令,那輸出結果全部都會匯集到 nohup.out 文件(容易混亂)

使用的腳本跟上面相同,不過在啟動腳本時改變啟動命令

A. 啟動命令改動如下


nohup ./normal_output.sh &

B. 查看 nohup.out 檔案:可以發現輸出結果到指定檔案,關閉終端不對輸出產生影響

● 如果你在腳本中使用 exec 另起一個進程輸出結果到檔案,那終端仍與 exec 啟動的進程有關聯,nohup 這時就無法中斷兩者(exec & 終端)之間的關聯


後台進程管理

管理進程可以使用 kill 命令對不同進程(指定 PID)來發送不同的信號,除了 kill 命令之外還有另一個常用的 jobs 命令

Jobs 查看後台進程

接下來使用這個腳本在背景運行,進行測試


#!/bin/bash

count=1

while [ $count -le 10 ] ; do

	sleep 10

	(( count++ ))
done

jobs 命令可以查看當前 Shell 正在處理的作業,並且它有幾個常用的 options,如下表

Options說明
-l列出進程的 PID & job 號
-n列出上次 Shell 發出的通知後改變的狀態
-p只列出 PID
-r列出運行中的作業
-s列出已停止的作業

jobs 列出的 +-

+ 號代表默認作業,- 下一個會被指定的作業在控制流程中,如果沒有指定作業號 就會用 +- 號 依序處理

背景運行腳本,並使用 jobs 命令查看任務

測試多背景作業下:符號 +- 號的改變

A. 啟動多個背景腳本,並使用 jobs -l 查看,可以看到+- 號只會有一組

B. 使用 kill 命令對當前是 + 號的進程發出 SIGKILL 命令,會發現 +- 號的轉移

在背景啟動暫停的作業:bg

bg 命令:該令令可以將暫停中的作業緩醒,並將該作業歸納到後台運行,bg 命令格式如下


bg [job 編號]

## 如果沒有指定,則依照 +- 號順序
bg

A. 啟動腳本


./job_3.sh

B. 暫停腳本使用 Ctrl + Z 快捷鍵,對腳本發出暫停信號(SIGTSTP

可以發現腳本被暫停 (Stopped)

C. 使用 bg 命令,來將暫停任務喚醒,並歸納到後台運行,再使用 jobs 查看任務是否真的在後台運行


./job_3.sh

將背景暫停作業切換到前景:fg

fg 命令:將在暫停中的作業,切換至前景(與使用者交互的進程)繼續運行;指令格式如下


jg [job 編號]

## 如果沒有指定,則依照 +- 號順序
jg

範例如下

A. 啟動耗時 Shell


./job_3.sh

B. 使用 Ctrl + Z 對腳本發出暫停訊號

C. 透過 jobs -l 查看當前 Shell 運行的相關任務


./jobs -l

D. 使用 fg 指令將其切換至當前交互介面繼續訓行


進程謙讓度

系統會根據進程的 謙讓度 來決定 CPU 資源的分配,如果謙讓度越低則分配的的資源越高,反知則越低

謙讓度 相關知識

● 範圍是 -20(資源分配高) ~ 19(資源分配低),值越小資源越多

● 使用者可以自由調高進程的謙讓度(數字提高),但是 只有 root 使用者可以調低謙讓度(數字降低)

調整謙讓度:nice / renice

nicerenice 兩個指令都可以調整腳本的謙讓度,兩者個差別在於 nice 是腳本尚未啟動時就設定,而 renice 則是腳本啟動後再做調整

nice 命令範例

Options功能
-n--adjustment調整謙讓度(預設為 10)

# 背景啟動耗時任務,並調整謙讓度到 10
nice -n 10 ./job_3.sh &

# 透過 ps 指令查看謙讓度... 等等訊息
ps -p 120437 -o pid,ppid,ni,cmd

renice 命令範例

renice 只能調整屬於自身的子進程謙讓度

Options功能
-n--adjustment調整謙讓度(預設為 10)
-p--pid指定 PID

# 背景啟動耗時任務,並調整謙讓度到 10
nice -n 10 ./job_3.sh &

# 透過 ps 指令查看謙讓度... 等等訊息
ps -p 120506 -o pid,ppid,ni,cmd

# 指定進程 ID,並調整謙讓度到 19
renice -n 19 -p 120506

# 再次檢查謙讓度... 等等訊息
ps -p 120506 -o pid,ppid,ni,cmd

● 再次提醒,要調低謙讓度(使用更多 CPU 資源)必須使用 root 用戶(或是 sudo 暫時調高權限)


定時運行腳本任務

Linux 系統可以透過特定命令來在固定(規劃好)的時間幫我們執行某些腳本

計畫執行:at 介紹

at 命令

有些 Linux 發行版中會沒有內建 at 命令,請透過以下命令安裝


sudo apt install -y at

at 命令:它會啟動一個守護進程 atd 在背景每 60s 進行檢查文件作業,而檢查的文件就是使用者排定的作業相關資訊

任務訊息文件所在位置

atd 維護的文件通常位於 /var/spool/cron/atjobs 目錄之下

at 命令格式如下


# timespec 用來指定作業時間

at [Options] timespec
Options說明
-f用來指定腳本文件
-q指定隊列(A to Z, a to z),對列則會影響到執行的優先級
-M永遠不發送 Mail 給使用者

● 如果你指定的 timespec 已經過了, 那它會在隔天的同個時段再去執行任務;而 timespec 有多種指定格式,以下列出幾種,詳細請看文件

A. 小時 & 分鐘

timespec 設定為 17:55

B. AM / PM 指示

timespec 設定為 05:55pm

C. 特殊時間命名now, noon, midnight, teatime

timespec 設定為 teatime

D. 標準日期格式月日年月/日/年月.日.年

timespec 設定為 10/10/23

E. 文本日期:加不加年都可以

timespec 設定為 Dec 25

F. 時間基礎運算 +

timespec 設定為 4pm + 3 days

timespec 設定為 10:15AM + 7 days

計畫執行:at 使用、相關命令

at 執行任務時的輸出

at 命令的 STDOUTSTDERR 預設會指向作業用戶的電子郵件,所以建議在使用 at 規劃時段時,最好將腳本內的指令重新導向


#!/bin/bash

echo "Hello at." 

sleep 3

echo "Finish at."

可以看到 如果正常的腳本透過 at 執行,STDOUT 並不會指向螢幕

at 命令也可以在互動式;結束設定時使用 ctrl + D


at 12:00

echo "吃飯囉~"

atq 查看等待的任務隊列


at -f ./at_1.sh tomorrow

at -M -f ./at_1.sh 12:30

at -M -f ./at_1.sh teatime

at -M -f ./at_1.sh now

atrm 移除排定作業

只能刪除自己提交的作業,無法刪除其他人提交的作業


atq

# 移除任務列表第二個任務
atrm 2

# 移除任務列表第三個任務
atrm 3

atq

定期執行腳本:cron 介紹

cronat 的差異cron 會定期執行,at 則是單次執行

cron 命令特性如下

A. cron 時間表:時間指定格式如下


min hour dayofmonth month dayofweek command

cron 允許時間使用特定值、範圍取值(eg. 1~5)、通配符... 等等,cron 的格式範例如下所示:


  • 每天 10:15 執行某個任務(指令)


15 10 * * * command


  • 每週三 10:15 執行某個任務(指令)

星期日(0)~ 星期六(6)


15 10 * * 3 command


  • 每月 5 號 10:15 執行某個任務(指令)

月初(1)~ 月底(31)


15 10 5 * * command

B. 任務指定:任務必需要使用「全路徑」指定

以下指令的含意是,每天 10:15 分執行 cron_1.sh 腳本


15 10 * * * /home/alien/Desktop/shell/chapter_16/cron_1.sh

C. 查看 cron 任務文件:它會放在 /etc 目錄下,並以 cron 開頭取名


ls -laF /etc/cron.*ly

定期執行腳本:crontab 使用

只有系統管理員可以直接使用 cron 命令,一般使用者想使用,就可以透過 crontab 命令操作(當然系統管理員也可以使用 crontab 命令)

使用者 crontab檔案編輯設定 crontab 任務

● 每個使用者都可以有自己的 crontab 檔案,通常存在 /var/spool/cron/crontabs 目錄下


sudo ls -laF /var/spool/cron/crontabs

A. 使用 crontab -e 編輯任務


# 指定使用的編輯系統
export=vim

# 編輯任務
crontab -e

B. 輸入 cron 規範格式去指定任務


15 10 * * * /home/alien/Desktop/shell/chapter_16/cron_1.sh

● 如果需要刪除某個任務,也必須透過 contab -e 編輯

使用 crontab -l 命令:查看 cron 任務的時間表


crontab -l

系統 corntab 檔案

系統的 corntab 檔案通常存在 /etc/crontab 檔案中,用它來安排系統任務的執行

從上圖可以看到每天 daily 會透過 run-parts 命令來運行 /etc/cron.daily 目錄下的所有命令(順序運行)

補足 cron 缺失:anacron 命令

anacron 命令

有些 Linux 發行版中會沒有內建 anacron 命令,請透過以下命令安裝


sudo apt install -y anacron

● 如果 cron 在定時時間啟動任務但電源沒開,那在 電源啟動後 cron 也不會去重新執行

這時就可以用 anacron 命令,它會盡快運行錯過時間的作業項目

A. anacorn 只會處理 cron 目錄下的程序,它有自己的文件去記錄每個指令應該運行的時機


ls -laF /var/spool/anacorn

B. anacorn 有自己的時間表,來檢查作業目錄


sudo cat /etc/anacrontab

啟動 Shell 即加載

請先複習 Shell 加載順序 這個章節,透過使用者啟動 Shell 時會加載的文件順序來把我們需要的指令(或腳本)加入

腳本插入 .bashrc

● 基本上除了最初在登入系統時一定會加載的 /etc/profile 文件之外,其他 以下文件都不一定會加載(每個發行版可能加載的文件都不同)

.bash_profile

.profile

.bash_login

但基本上這些文件最終基本上都會加載(呼叫)到 .bashrc 文件,所以我們只要編輯該文件,就可以在每個 bash 中插入指令

A. 透過 vim .bashrc


vim .bashrc

B. 插入一行簡單指令,保存並退出


echo "Hello Bash"

C. 重新啟動一個新 bash 介面 就會發現指令被輸出了~


更多 Linux Shell 知識

探索 Debian 系統上的套件管理系統(PKMS 概念)| 套件倉庫

Linux 環境、服務:用戶、權限管理

Linux 環境、服務、管理

在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…

了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版

在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異

探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制

這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式

Linux 系統管理入門:安全性、用戶管理與權限設定指南

在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作

認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定

這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(Pluggable Authentication Modules)設定

Linux Shell 相關知識

Linux Shell 相關知識

這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…

Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算

認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令

這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法

Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數

學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數

探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算

這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算

Shell 結構化

Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷

該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷

掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環

接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧

探索 Shell 函數與腳本庫 | Shell 結構化 & 函數

這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間

Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動

不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取

Shell script 進階

Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件

掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊

探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本

信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間

Linux 硬體規劃:檔案系統、分區

Linux 硬體規劃:檔案系統、分區

最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…

Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案

這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統

深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode

學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制

理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心

這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響