Linux
如何監控由空字節填充的文件的變化?
我有一個由空字節填充的 10Mb 文件。程序正在訪問它並將零更改為特定字元串,直到文件末尾。
我嘗試使用
tail -F | grep wanted_text | grep -v "unwanted_text"
,但它不監視更改。它僅適用於通常的文本文件,但不適用於由零填充的文件。所有空字節都被替換為由換行符分隔的行,直到文件末尾。文件填滿後,它被重命名,而是創建新文件。
那麼如何通過過濾輸出來監視由空字節填充的文件的變化呢?
這是 Reader 的腳本,它應該接近於為 NUL 填充文件偽造 tail 命令所需的內容。它檢查文件中的更改(通過比較整個 ls -l 輸出,其中包括低至納秒的時間戳),並報告批處理中的任何添加。它在啟動時不報告文件中已經存在的行,僅在執行時添加。
它以兩種速度執行,以避免浪費檢查。如果它檢測到任何添加,它會在 1.0 秒後再次嘗試。如果一個循環沒有看到任何添加,它會在 5 秒後再次嘗試(這 5 是該過程的參數)。
#! /bin/bash #: Reader: tail -f a file which is pre-formatted with many trailing NUL characters. #### Implement the User Requirement. function Reader { local RUN="${1:-60}" SLEEP="${2:-5}" FILE="${3:-/dev/null}" local AWK=''' BEGIN { NUL = "\000"; } function Tick (Local, cmd, ts) { cmd = "date \047+%s\047"; cmd | getline ts; close (cmd); return (ts); } function TS (Local, cmd, ts) { cmd = "date \047+%H:%M:%S.%N\047"; cmd | getline ts; close (cmd); return (ts); } function Wait (secs) { system (sprintf ("sleep %s", secs)); } function isChange (Local, cmd, tx) { cmd = sprintf ("ls 2>&1 -l --full-time \047%s\047", Fn); cmd | getline tx; close (cmd); if (tsFile == tx) return (0); tsFile = tx; if (index (tx, "\047")) { if (fSt != "B") { fSt = "B"; printf ("%s: No file: %s\n", TS( ), Fn); } } else { if (fSt != "G") { fSt = "G"; printf ("%s: Reading: %s\n", TS( ), Fn); } } return (1); } function atNul (buf, Local, j) { j = index (buf, NUL); return ((j > 0) ? j : 1 + length (buf)); } function List (tx, Local, ts, X, j) { sub ("\012$", "", tx); split (tx, X, "\012"); ts = TS( ); for (j = 1; j in X; ++j) { printf ("%s %3d :%s:\n", ts, length (X[j]), X[j]); } } function Monitor (Local, rs, tk, Buf, Now, End) { printf ("%s: READER Begins\n", TS( )); tk = Tick( ); Expired = tk + Run; Now = -1; while (Tick( ) <= Expired) { if (! isChange( )) { Wait( Sleep); continue; } rs = RS; RS = "\000"; Buf = ""; getline Buf < Fn; close (Fn); RS = rs; if (Now < 0) Now = atNul( Buf); End = atNul( Buf); List( substr (Buf, Now, End - Now)); Now = End; Wait( 1.0); } printf ("%s: READER Exits\n", TS( )); } NR == 1 { Run = $0; next; } NR == 2 { Sleep = $0; next; } NR == 3 { Fn = $0; } END { Monitor( Fn); } ''' { echo "${RUN}"; echo "${SLEEP}"; echo "${FILE}"; } | awk -f <( echo "${AWK}" ) } #### Script Body Starts Here. Reader 40 5 "./myNullFile"