如何在 bash 中的數組值中保留文字表達式中的空格以及如何修剪排序命令的結果?
在搜尋日誌文件中的表達式的上下文中,我一般想知道是否有一種方法可以以某種方式量化和限定日誌的內容
/var/log
。特別是,用於描述錯誤情況的詞典是否符合一般預期,以及術語在日誌中有何不同。為了進一步調查並驗證這些期望,我製作了這個小腳本來檢查、計數和排序一些事情:#!/bin/bash # Meh - In /var/log, (1) for each file count lines which # contain matches for expressions in the set; then, # (2), iterate files again and sort (all) words in a file # by descending frequency. FILES="/var/log/* /var/log/**/* /var/log/**/**/*" WORDS=(error fail.* wrong bad break panic abort.* disaster problem issue 'couldn'\''t' 'didn'\''t' 'wasn'\''t' 'shouldn'\''t' 'isn'\''t' 'don'\''t' "is'\ 'not" 'did\ not' die.* crash.* dump.* seg.* bug.* report.* status) # Header section 1 printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - printf 'Matches for expressions in set\n' printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - # (1) for f in $FILES do for w in ${WORDS[@]} do echo -n "$f [$w]:" grep -aci $w $f 2>/dev/null done printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - done # Header section 2 printf 'Sorted occurences for all words in a file\n' printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - # (2) for f in $FILES do echo "[total number of lines: $(wc -l $f 2>/dev/null)]" cat $f 2>/dev/null | tr -c '[:alnum:]' '[\n*]' | tr -d '[:digit:]' | sort -f | uniq -ci | sort -fnr printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - done exit
無論多麼粗糙和有缺陷,它都達到了讓我瞥見頻率並在一定程度上驗證集合的目的。例如,這是
dmesg
我係統上的一些範例輸出:/var/log/dmesg [error]:27 /var/log/dmesg [fail.*]:7 /var/log/dmesg [wrong]:0 /var/log/dmesg [bad]:0 /var/log/dmesg [break]:0 /var/log/dmesg [panic]:1 /var/log/dmesg [abort.*]:0 /var/log/dmesg [disaster]:0 /var/log/dmesg [problem]:0 /var/log/dmesg [issue]:0 /var/log/dmesg [couldn't]:2 /var/log/dmesg [didn't]:0 /var/log/dmesg [wasn't]:0 /var/log/dmesg [shouldn't]:0 /var/log/dmesg [isn't]:0 /var/log/dmesg [don't]:0 /var/log/dmesg [is'\]:/var/log/dmesg ['not]:0 <------ /var/log/dmesg [did\]:/var/log/dmesg [not]:14 <------ /var/log/dmesg [die.*]:0 /var/log/dmesg [crash.*]:0 /var/log/dmesg [dump.*]:0 /var/log/dmesg [seg.*]:0 /var/log/dmesg [bug.*]:3 /var/log/dmesg [report.*]:1 /var/log/dmesg [status]:28 [total number of lines: 1059 /var/log/dmesg] 14784 306 usb 220 pci 133 x 128 hub 116 acpi 113 d 109 mem 95 a 94 uhci 76 hcd 76 device 73 bus 56 io 55 to 54 port 54 e 54 ata 53 c 51 power 48 interface 47 registered 46 ehci 40 system 40 for 38 new 37 sda 37 bridge 36 on 36 irq 34 type 34 reset 34 probe 34 nouveau 33 v 33 sd 31 reserved 30 memory 29 f 27 ports 27 found 27 error 27 and 26 resource 26 reg 26 input 26 driver 25 id 25 i 23 window 23 disabled 22 xc 22 status 22 from 22 drm 22 bit ...
“錯誤”是我的設置中最重要的“問題詞”,或者很多與硬體相關的條目出現在
dmesg
.問題
如何在數組值列表中保留由兩個單詞(“is not”、“did not”)組成的文字表達式的值中的空間?嘗試了 ‘did’\040’not’ 或 “did’'not” 以及許多變體。不確定如何應用此問答中的資訊。
當第二個循環(2)最終輸出日誌中每個唯一出現的單詞時,如何限制它的範圍或我應該如何丟棄:
- 由單個字元組成的輸出?
- 由單個事件組成的輸出?
是否有任何視覺化呈現輸出的建議,或者是否有工具可以為搜尋或格式化計數和單詞數據提供更多功能?
使用 shell 變數時,您可以通過用雙引號將 shell 變數括起來來保留空格字元(更準確地說,防止值根據欄位分隔符拆分為單詞,這些字元在 $IFS shell 變數中列舉)。
for w in "${WORDS[@]}" do echo -n "$f [$w]:" grep -aci "$w" $f 2>/dev/null done
(
$f
如果您遇到帶有空格的文件名,也可以用引號括起來。)當第二個循環(2)最終輸出日誌中每個唯一出現的單詞時,如何限制它的範圍或我應該如何丟棄:
由單個字元組成的輸出?
grep ..
在管道中添加以僅包含具有 2 個或更多字元的行。由單個事件組成的輸出?
添加
-d
到uniq
管道中,這樣它就只會顯示重複的行。cat $f 2>/dev/null | tr -c '[:alnum:]' '[\n*]' | tr -d '[:digit:]' | sort -f | grep .. | uniq -dci | sort -fnr
是否有任何視覺化呈現輸出的建議,或者是否有工具可以為搜尋或格式化計數和單詞數據提供更多功能?
有很多應用程序可以掃描和總結日誌文件中有趣的事件,有些是免費的,有些是商業的。我不確定我們是否可以提供廣泛的建議,但如果您可以提供您想提出的查詢範例或您想查看的輸出格式,也許我們可以回答這些類型的問題。