歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

Linux進階必學知識:grep是什麼?怎麼用?

三年前,作為面試官,我負責招聘unix系統管理員。那次來競聘該崗位的共有8個人,其中兩人是技術一流的自由職業者。我認為系統管理員沒必要把所有的配置方法熟記於心,需要某個軟件的時候,只要你想把它玩轉並且玩得更酷,多讀些文章,你便會自然而然地熟悉它的各種用法與配置。於是,我讓這些應聘者解決下面兩個問題:

  1. 創建一個例行任務,它在每個偶數點(比如2點、12點)和3點執行;
  2. 通過/var/run/dmesg.boot文件打印處理器信息。

讓我吃驚的是,8位應聘者中沒有一個人能解決上述問題,其中兩人竟對grep命令一無所知。

介於此,我們就好好說說grep。

首先,以下所有的操作都是基於grep 2.5.1-FreeBSD:

# grep --version | grep grep
grep (GNU grep) 2.5.1-FreeBSD

有必要先交待下grep版本,因為某些用法只限定於特定的版本:

# man grep | grep -iB 2 freebsd
       -P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This option  is
              not supported in FreeBSD.

好了,言歸正傳,我們經常會這樣grep文件:

root@nm3:/ # cat /var/run/dmesg.boot | grep CPU:
CPU: Intel Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

還可以這樣做:

root@nm3:/ # grep CPU: /var/run/dmesg.boot
CPU: Intel Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

這樣也是可以的(雖然我很討厭這種操作方式):

root@nm3:/ # </var/run/dmesg.boot grep CPU:
CPU: Intel Core(TM)2 Quad CPU    Q9550  @ 2.83GHz (2833.07-MHz K8-class CPU)

你肯定會遇到這樣的場景:統計文件中帶有某些關鍵字的行出現的次數。grep+wc可以幫到你:

root@nm3:/ # grep WARNING /var/run/dmesg.boot | wc -l
       3

條條大路通羅馬,下面是另一條路:

root@nm3:/ # grep WARNING /var/run/dmesg.boot -c
3

下面我們新建一個測試用的文檔:

root@nm3:/ # grep ".*" test.txt
one two three
seven eight one eight three
thirteen fourteen fifteen
 sixteen seventeen eighteen seven
sixteen seventeen eighteen
        twenty seven
one 504 one
one 503 one
one     504     one
one     504 one
#comment UP
twentyseven
        #comment down
twenty1
twenty3
twenty5
twenty7

繼續grep的搜索之旅。

-w選項指定要搜索的單詞:

root@nm3:/ # grep -w 'seven' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
        twenty seven

如果想搜以特定字符開頭(結尾)的單詞,可以這樣:

root@nm3:/ # grep '<seven' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
sixteen seventeen eighteen
        twenty seven
root@nm3:/ # grep 'seven>' test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
        twenty seven
twentyseven

如果想搜以特定字符開頭(結尾)的行,可以這樣:

root@nm3:/ # grep '^seven' test.txt
seven eight one eight three
root@nm3:/ # grep 'seven$' test.txt
 sixteen seventeen eighteen seven
        twenty seven
twentyseven
root@nm3:/ #

想要顯示目標行的上下文嗎?

root@nm3:/ # grep -C 1 twentyseven test.txt
#comment UP
twentyseven
        #comment down

到底是顯示上文還是下文?

root@nm3:/ # grep -A 1 twentyseven test.txt
twentyseven
        #comment down
root@nm3:/ # grep -B 1 twentyseven test.txt
#comment UP
twentyseven

我們還可以這樣玩grep:

root@nm3:/ # grep "twenty[1-4]" test.txt
twenty1
twenty3

或者取非:

root@nm3:/ # grep "twenty[^1-4]" test.txt
        twenty seven
twentyseven
twenty5
twenty7

grep是個強大的指令,除上述列舉的之外,它還支持許多限定符、通配符以及正則表達式。下面是一些例子:

root@nm3:/ # cat /etc/resolv.conf
#options edns0
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

只獲取IP地址相關的行:

root@nm3:/ # grep -E "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}" /etc/resolv.conf
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

上面的方法可行,但下面這種方法更好:

root@nm3:/ # grep -E 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf
#nameserver 127.0.0.1
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

希望去掉注釋行?

root@nm3:/ # grep -E 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf | grep -v '#'
nameserver 8.8.8.8
nameserver 77.88.8.8
nameserver 8.8.4.4

只要IP:

root@nm3:/ # grep -oE 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf | grep -v '#'
127.0.0.1
8.8.8.8
77.88.8.8
8.8.4.4

哎呀,被注釋掉的127.0.0.1又回來了,這是指令執行順序不當導致的,怎麼破?

root@nm3:/ # grep -v '#' /etc/resolv.conf | grep -oE 'b[0-9]{1,3}(.[0-9]{1,3}){3}b'
8.8.8.8
77.88.8.8
8.8.4.4

下面看下-v(反向查找)選項的使用。

假設要執行指令“ps –afx | grep ttyv ”:

root@nm3:/ # ps -afx | grep ttyv
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7
48798  2  S+        0:00.00 grep ttyv

OK,但是我們不需要“48798 2 S+ 0:00.00 grep ttyv”一行,使用-v:

root@nm3:/ # ps -afx | grep ttyv | grep -v grep
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7

看著不爽?現在呢?

root@nm3:/ # ps -afx | grep "[t]tyv"
 1269 v1  Is+       0:00.00 /usr/libexec/getty Pc ttyv1
 1270 v2  Is+       0:00.00 /usr/libexec/getty Pc ttyv2
 1271 v3  Is+       0:00.00 /usr/libexec/getty Pc ttyv3
 1272 v4  Is+       0:00.00 /usr/libexec/getty Pc ttyv4
 1273 v5  Is+       0:00.00 /usr/libexec/getty Pc ttyv5
 1274 v6  Is+       0:00.00 /usr/libexec/getty Pc ttyv6
 1275 v7  Is+       0:00.00 /usr/libexec/getty Pc ttyv7

別忘了| (或)符號:

root@nm3:/ # vmstat -z | grep -E "(sock|ITEM)"
ITEM                   SIZE  LIMIT     USED     FREE      REQ FAIL SLEEP
socket:                 696, 130295,      30,      65,   43764,   0,   0

殊途同歸:

root@nm3:/ # vmstat -z | grep "sock|ITEM"
ITEM                   SIZE  LIMIT     USED     FREE      REQ FAIL SLEEP
socket:                 696, 130295,      30,      65,   43825,   0,   0

許多人都會在grep中用正則表達式,但你仍會忘了用POSIX字符集,即便它們也非常有用。

POSIX:

[:alpha:] Any alphabetical character, regardless of case
[:digit:] Any numerical character
[:alnum:] Any alphabetical or numerical character
[:blank:] Space or tab characters
[:xdigit:] Hexadecimal characters; any number or A–F or a–f
[:punct:] Any punctuation symbol
[:print:] Any printable character (not control characters)
[:space:] Any whitespace character
[:graph:] Exclude whitespace characters
[:upper:] Any uppercase letter
[:lower:] Any lowercase letter
[:cntrl:] Control characters

找有大寫字母的行:

root@nm3:/ # grep "[[:upper:]]" test.txt
#comment UP

搜索結構不夠醒目?高亮顯示:

grep1

更多的grep小竅門。第一個稍顯專業,我已經15年沒用過了。

選擇包含six,seven或者eight的行,很簡單:

root@nm3:/ # grep -E "(six|seven|eight)" test.txt
seven eight one eight three
 sixteen seventeen eighteen seven
sixteen seventeen eighteen
        twenty seven
twentyseven

那麼現在只選擇包含six,seven或者eight若干次的行。這種用法叫回溯引用:

root@nm3:/ # grep -E "(six|seven|eight).*1" test.txt
seven eight one eight three
 sixteen seventeen eighteen seven

第二個竅門,這個更有用一些。打印504前後有tab的行(如果PCRE能夠支持這個特性就好了)。

POSIX字符集在此失效了:

root@nm3:/ # grep "[[:blank:]]504[[:blank:]]" test.txt
one 504 one
one     504     one
one     504 one

[CTRL+V][TAB]生效:

root@nm3:/ # grep "     504     " test.txt
one     504     one

我漏講什麼了嗎?grep具備遞歸搜索文件/目錄功能。如果我們想在源碼目錄中搜索允許Intel使用外部SFPs的代碼,但是又沒清楚完整地記著函數名allow_unsupported_stp和unsupported_allow_sfp。腫麼辦?這正是grep的菜:

root@nm3:/ # grep -rni allow /usr/src/sys/dev/ | grep unsupp
/usr/src/sys/dev/ixgbe/README:75:of unsupported modules by setting the static variable 'allow_unsupported_sfp'
/usr/src/sys/dev/ixgbe/ixgbe.c:322:static int allow_unsupported_sfp = TRUE;
/usr/src/sys/dev/ixgbe/ixgbe.c:323:TUNABLE_INT("hw.ixgbe.unsupported_sfp", &allow_unsupported_sfp);
/usr/src/sys/dev/ixgbe/ixgbe.c:542: hw->allow_unsupported_sfp = allow_unsupported_sfp;
/usr/src/sys/dev/ixgbe/ixgbe_type.h:3249: bool allow_unsupported_sfp;
/usr/src/sys/dev/ixgbe/ixgbe_phy.c:1228: if (hw->allow_unsupported_sfp == TRUE) {
 

希望你還沒暈,因為這些grep用法只是grep的冰山一角呢!

最後祝大家 Happy grepping!

Copyright © Linux教程網 All Rights Reserved