介紹如何在 Linux 系統上透過 inotify-tools
指令工具,監控檔案的各種變動,觸發對應的處理動作。
inotify(代表 inode notify)是一個 Linux 核心子系統,負責監看檔案系統並將任何檔案變動通知應用程式,可用於自動更新目錄顯示、重新載入設定檔、記錄檔、備份檔案或上傳檔案。
inotify-tools
工具大部分的 Linux 發行版的套件庫中,都有收錄 inotify-tools
工具,使用對應的套件管理工具安裝 inotify-tools
套件即可:
# 安裝 inotify-tools 套件(Debian/Ubuntu) sudo apt install inotify-tools # 安裝 inotify-tools 套件(Fedora) sudo yum install inotify-tools # 安裝 inotify-tools 套件(RHEL/CentOS) sudo yum install -y epel-release && yum update sudo yum install inotify-tools
關於其他各種 Linux 環境的安裝方式,可以參考 inotify-tools 的說明。
inotifywait
指令是 inotify-tools
套件所提供的工具之一,可以用來監看指定的檔案變動事件,並觸發對應的動作。
如果要監看 /tmp
目錄下所有的檔案事件,可以執行:
# 持續監看 /tmp 目錄下的所有檔案事件 inotifywait -m /tmp
Setting up watches. Watches established.
執行 inotifywait
之後,會占用一個終端機,並將所有檔案事件的訊息輸出在終端機中。這裡的 -m
參數是代表讓 inotifywait
持續獨斷監看檔案事件(如果沒有加上此參數,預設會在收到一筆檔案事件之後就停止監看)。
接著開啟另外一個終端機,執行一些檔案的操作:
# 進行一些檔案操作 date > /tmp/date.output rm /tmp/date.output
這時候就會看到 inotifywait
的輸出中出現以下的檔案事件訊息:
/tmp/ CREATE date.output /tmp/ OPEN date.output /tmp/ MODIFY date.output /tmp/ CLOSE_WRITE,CLOSE date.output /tmp/ DELETE date.output
如果要對指定目錄與其子目錄下的所有檔案進行監看,可以加上 -r
參數以遞迴的方式監看:
# 持續監看 /tmp 目錄與子目錄下的所有檔案事件(遞迴) inotifywait -m -r /tmp
inotifywait
也可以針對特定的檔案進行監看,例如監看 /var/log/syslog
這個系統記錄檔的檔案事件:
# 持續監看 /var/log/syslog 檔案的所有事件 inotifywait -m /var/log/syslog
Setting up watches. Watches established. /var/log/syslog MODIFY
我們可以使用 --format
自訂輸出訊息的格式:
# 自訂輸出訊息格式 inotifywait -m --format "%:e %f" /tmp
CREATE date.output OPEN date.output MODIFY date.output CLOSE_WRITE:CLOSE date.output DELETE date.output
事件訊息格式支援以下幾種轉換代碼:
代碼 | 說明 |
---|---|
%w |
觸發事件的監看檔案。 |
%f |
若事件發生在目錄之內,則顯示觸發事件的檔案,否則為空字串。 |
%e |
發生事件,以逗號區隔。 |
%Xe |
發生事件,以 X 符號區隔。 |
%T |
時間,可用 --timefmt 參數指令時間格式。 |
inotifywait
在預設的狀況下會傾聽所有的檔案事件:
名稱 | 說明 |
---|---|
access |
讀取檔案。 |
modify |
寫入檔案。 |
attrib |
更改檔案屬性,例如修改時間、權限等。 |
close_write |
檔案從寫入模式關閉,但不代表有實際寫入資料。 |
close_nowrite |
檔案從唯讀模式關閉。 |
close |
關閉檔案,等同於 close_write 與 close_nowrite 。 |
open |
開啟檔案。 |
moved_to |
檔案或目錄移入監看目錄,包含監看目錄內的搬移。 |
moved_from |
檔案或目錄移出監看目錄,包含監看目錄內的搬移。 |
move |
搬移檔案或目錄,等同於 moved_to 與 moved_from 。 |
move_self |
移動監看目錄本身,搬移之後該目錄就會脫離監看範圍。 |
create |
建立檔案或目錄。 |
delete |
刪除檔案或目錄。 |
delete_self |
刪除監看目錄本身。 |
unmount |
卸載監看目錄本身,卸載之後該目錄就會脫離監看範圍。 |
若要監看 /tmp
目錄之下所有檔案的建立(create
)與刪除(delete
)事件:
# 持續監看 /tmp 目錄下的 create 與 delete 檔案事件 inotifywait -m -e create -e delete /tmp
Setting up watches. Watches established. /tmp/ CREATE sh-thd.3CAUNM /tmp/ DELETE sh-thd.3CAUNM
inotifywait
預設會將檔案事件訊息都輸出在標準錯誤(stderr),若要將訊息儲存至檔案,可以使用 -o
參數指定輸出的檔案:
# 將事件訊息輸出至 events.log inotifywait -m -o events.log /tmp
若要將事件訊息輸出至系統的 syslog 中,可以加上 -s
參數:
# 將事件訊息輸出至系統的 syslog inotifywait -m -s /tmp
inotifywait
加上 -d
參數即可以背景 daemon 的方式執行,而通常這種方式都會搭配 -o
或 -s
將事件訊息輸出至檔案:
# 背景執行,事件訊息輸出至 syslog inotifywait -m -d -s /tmp
以下是一些搭配 inotifywait
指令所撰寫的實際應用指令稿。
如果要監看指定目錄,當目錄中有新增檔案時,對新檔案作立即性的處理,可以使用以下指令稿進行修改:
# 監看 myfolder 目錄中新增的檔案,觸發指定動作 inotifywait -m -e create -e moved_to myfolder | while read dir action file; do echo "$dir 目錄透過 $action 方式新增檔案 $file" # 進行後續處理 ... done
Setting up watches. Watches established. myfolder/ 目錄透過 CREATE 方式新增檔案 test1.txt myfolder/ 目錄透過 MOVED_TO 方式新增檔案 myscript.sh
以下指令稿可用來監看 /var/log/auth.log
這個使用者登入的記錄檔,篩選出使用者都入系統的記錄,每當有使用者登入時,觸發對應的處理動作:
# 監看 /var/log/auth.log 檔案內容變動 while inotifywait -e modify /var/log/auth.log; do # 取得檔案最後一行內容 new_msg=`tail -n1 /var/log/auth.log` # 檢查內容是否包含 systemd-logind 這個關鍵字,並取出使用者名稱 if [[ $new_msg =~ systemd-logind.*user(.*)\. ]]; then echo "使用者登入:${BASH_REMATCH[1]}" # 進行後續處理 ... fi done
Setting up watches. Watches established. /var/log/auth.log MODIFY Setting up watches. Watches established. /var/log/auth.log MODIFY 使用者登入: ubuntu
inotifywatch
可以用來統計指定路徑之下的檔案事件,例如統計 /var/log
目錄下的 access
與 modify
檔案事件:
# 統計 /var/log 目錄下的 access 與 modify 檔案事件 inotifywatch -v -e access -e modify -t 60 -r /var/log
Establishing watches... Setting up watch(es) on /var/log OK, /var/log is now being watched. Total of 15 watches. Finished establishing watches, now collecting statistics. Will listen for events for 60 seconds. total access modify filename 79 42 37 /var/log/ 12 4 8 /var/log/journal/b8484d93cddf4bff9e38ce21e93587ea/ 4 4 0 /var/log/journal/