在 Unix 系統上查詢資料的最佳工具和技巧

Sandra Henry-Stocker發表於2015-10-19

有時候在 Unix 系統上查詢資訊就如同大海撈針。如果重要的資訊被淹沒在大量文字中,它們也很難被注意到。目前我們中的很多人都在處理“大資料” —— 從數十億位元組大小的日誌檔案和巨大的各種格式記錄集合中挖掘商業情報。

幸運的是,只有在兩種情況下,你才需要在成堆的資料中挖掘,繼而完成你的工作 —— 當你知道你要找什麼和當你不知道的時候。:) 最佳工具和技巧取決於你面臨兩種情況中的哪一種。

當你知道的時候

當你知道你要找什麼,grep 就是你的朋友,這不只是在你查詢特定文字的時候。grep 命令可以幫助你找到任意文字,特定單詞,文字模式和有上下文的文字。當你知道文字長什麼樣時,查詢它通常很簡單。grep this that 命令會顯示“that”檔案中包含“this”字串的每一行。增加 -w 選項就只會顯示那些單獨包含“this”這個單詞的行。換句話說,如果行中包含“thistle” 或 “erethism” 就不會顯出來,除非這些行也有 “this” 這個單詞。

最簡單的 grep 命令不費什麼力氣就能理解:

$ grep find poem
finding meaning, finding comfort,
finding someone to adore
Can we find a way to be

查詢整個單詞可以透過增加 -w 選項完成:

$ grep -w find poem
Can we find a way to be

查詢模式需要一點技巧。我們的第一個例子中顯示了包含“find”單詞的行,無論“find”中的“f”是大寫還是小寫:

$ grep [Ff]ind poem
Finding answers
finding meaning, finding comfort,
finding someone to adore
Can we find a way to be

如果你想匹配以文字起始或結束的行,你可以使用 ^(起始)或 $(結尾)。

$ grep ^find poem
finding meaning, finding comfort,
finding someone to adore

如果你想找到包含兩個連續母音音節的單詞的行,你可以使用如下所示的“AEIOUaeiou”字元。

$ grep -E "[AEIOUaeiou]{2}" poem | head -3
All our days are filled with searching
wondering what we're looking for
finding meaning, finding comfort,

查詢包含 9 個或者 10 個字母的字串:

$ grep -E "[[:alpha:]]{9,10}" poem
All our days are filled with searching
wondering what we're looking for
All our days are filled with searching
that makes the searching more productive

查詢一個包含 “find” 的長單詞:

$ grep -E "find[^[:space:]]+" poem
finding meaning, finding comfort,
finding someone to adore

我們中的大多數人不會去查詢詩歌,這是顯而易見的,但我們可以使用同樣的技巧來從我們的系統檔案中獲取相關的資訊。在下面的例子裡,我們查詢”processor”這個術語,並且按照五行一組(前置兩行後置兩行)顯示出來以便提供一些上下文。如果你希望得到 9 行一組,將 -C 2 變成 -C 4 就可以了。

$ grep -C 2 processor /var/log/dmesg
Using ACPI (MADT) for SMP configuration information
Allocating PCI resources starting at 88000000 (gap: 80000000:7ec00000)
Detected 3400.426 MHz processor.
Built 1 zonelists.  Total pages: 524275
Kernel command line: ro root=LABEL=/1
--
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 2071140k/2097100k available (2223k kernel code, 24616k reserved, 922k data, 232k init, 1179596k highmem)
Checking if this processor honours the WP bit even in supervisor mode... Ok.
Calibrating delay loop (skipped), value calculated using timer frequency.. 6800.85 BogoMIPS (lpj=3400426)
Security Framework v1.0.0 initialized
--
CPU0: Intel(R) Xeon(TM) CPU 3.40GHz stepping 04
SMP alternatives: switching to SMP code
Booting processor 1/1 eip 11000
CPU 1 irqstacks, hard=c0779000 soft=c0759000
Initializing CPU
#1
--
CPU1: Intel(R) Xeon(TM) CPU 3.40GHz stepping 04
SMP alternatives: switching to SMP code
Booting processor 2/6 eip 11000
CPU 2 irqstacks, hard=c077a000 soft=c075a000
Initializing CPU
#2
--
CPU2: Intel(R) Xeon(TM) CPU 3.40GHz stepping 04
SMP alternatives: switching to SMP code
Booting processor 3/7 eip 11000
CPU 3 irqstacks, hard=c077b000 soft=c075b000
Initializing CPU
#3

當你不知道的時候

如果你要查詢一個已知位置的文字,例如當 Perl 告訴你指令碼執行到第 73 行出現了問題,或者你正在處理檔案的第 1892 行,你可以使用sed 來顯示特定的行(我只是不喜歡數到 1892 行)。而且額外花一點點力氣,你就可以只顯示這一行。

錯誤資訊可能像這個樣子:

“syntax error line 73 near ”} else“ ”

你可以使用一個sed命令來顯示出問題的這行:

$ sed -n 73p showvars
else

好了,就是這行,但是我們也沒有比之前多知道些什麼。透過顯示前面幾行可以增加一點上下文資訊,我們就可以定位錯誤。這裡有一個類似的命令可以顯示這行和之前的十行:

$ sed -n 63,73p showvars
if $password eq "a_secret";
{
    foreach $var (sort(keys(%ENV))) {
        $val = $ENV{$var};
        $val =~ s|n|n|g;
        $val =~ s|"|"|g;
        print '${var}="${val}"n'
    };
}
else

哎呦!這看上去是某些人在寫 if 語句時出了問題!我們可以很容易地修復它。

你還可以使用 sed 命令來強調包含特定內容的行。在下面的命令裡,我們增加了一個 “箭頭標記” 來強調每一個包含 foreach 命令的行:

$ sed '/print/{b label1; {:label1 ; s/^/# / ; s/$/ <===/ ;} }' showvars
#!/bin/bash
 
if $password eq "a_secret";
{
    foreach $var (sort(keys(%ENV))) {
        $val = $ENV{$var};
        $val =~ s|n|n|g;
        $val =~ s|"|"|g;
#         print '${var}="${val}"n' <===
    };
}
else

你可以使用類似的命令註釋掉你的 print 命令:

$ sed '/print/{b label1; {:label1 ; s/^/# / ; s/$/ <===/ ;} }' showvars
#!/bin/bash
 
if $password eq "a_secret";
{
    foreach $var (sort(keys(%ENV))) {
        $val = $ENV{$var};
        $val =~ s|n|n|g;
        $val =~ s|"|"|g;
#         print '${var}="${val}"n' <===
    };
}
else

大海撈針很難,其實地毯上找針也都不容易。但是透過使用一些最常見 Unix 命令的變形,就可以很容易找到你要找的東西,甚至當你並不知道要找什麼的時候。

相關文章