Linux技巧:多實例介紹 grep 命令的常見用法


Linux技巧:多實例介紹 grep 命令的常見用法

在 Linux 命令中,grep 命令是最常用的命令之一。下面基於實例介紹 grep 命令的常見用法。

  • grep 命令格式
  • 查找多個文件
  • 匹配模式為空字符串時會匹配所有行
  • 顏色高亮匹配到的模式字符串
  • 使用 -r 選項指定查找所給目錄、及其子目錄的所有文件
  • 使用 --exclude 或 --include 指定過濾特定的文件名
  • 使用 -w 選項指定全詞匹配
  • 使用 -n 選項指定打印所匹配行的行號
  • 使用 -i 選項指定忽略大小寫
  • 使用 -v 選項指定打印不匹配的行
  • 使用 -e 選項分別指定多個模式字符串
  • 使用基本正則表達式來指定匹配模式
  • 使用擴展正則表達式來指定匹配模式
  • 使用 -q 選項指定不打印任何內容
  • 使用 -A、-B、或 -C 選項查看匹配行前後的內容
  • 使用 -l 選項只打印文件名,不打印匹配的行內容
  • 結合 find、xargs 命令一起使用

grep 命令格式

查看 man grep 對 grep 命令的說明如下:

  • grep - print lines matching a patterngrep [OPTIONS] PATTERN [FILE...]grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
  • grep searches the named input FILEs (or standard input if no files are named, or if a single hyphen-minus (-) is given as file name) for lines containing a match to the given PATTERN.
  • By default, grep prints the matching lines.
  • The exit status is 0 if selected lines are found, and 1 if not found. If an error occurred the exit status is 2.

即,grep 命令在所給文件中查找特定模式的字符串,可以提供多個文件名,在多個文件中查找。

如果沒有提供文件名,則讀取標準輸入。

默認會打印出包含特定模式的整行內容,以便查看是哪一行包含了這個模式。

注意:跟在 grep 命令的 PATTERN 參數後面的參數會被認為是文件名,即使用引號把參數值括起來也還是當成文件名,不會當成字符串。

剛接觸 grep 命令的常見誤區是,以為用雙引號把參數值括起來就變成查找字符串,這是錯誤的用法。

具體舉例說明如下:

<code>$ cat testfile
This is a test string.
$ grep "string" testfile
This is a test string.
$ grep "string" "testfile"
This is a test string.
$ grep "string" "This is a test string."
grep: This is a test string.: No such file or directory
/<code>

可以看到,當前目錄下有一個 testfile 文件,它裡面只有一行 "This is a test string." 字符串。

grep "string" testfile 命令會在 testfile 文件中查找 "string" 字符串,找到後打印出對應的行。

grep "string" "testfile" 命令也是在 testfile 文件中查找 "string" 字符串,即使用雙引號把 testfile 括起來,也不代表是在 "testfile" 字符串中查找 "string" 字符串。

而 grep "string" "This is a test string." 命令會執行報錯,提示找不到名為 This is a test string. 的文件,它不是在 "This is a test string." 字符串中查找 "string" 字符串。

如果確實需要用 grep 命令來查找字符串,可以用管道操作符 | 來連接標準輸入。

例如用 echo 命令打印字符串的值,然後通過管道操作符把這個值傳遞到 grep 命令的標準輸入。

舉例如下:

<code>$ echo "This is a test string." | grep string
This is a test string.
$ value="This is a new test string."
$ echo "$value" | grep new
This is a new test string.
$ echo $?
0
/<code>

可以看到,echo "This is a test string." | grep string 命令通過 echo 先輸出字符串的值,再通過管道操作符 | 把這個輸出連接到 grep 命令的標準輸入,就能查找字符串,不會執行報錯。

echo "$value" | grep new 命令在 value 變量值中查找 "new" 字符串,grep 命令在查找到匹配模式時,會返回 0,也就是 true。

可以使用 $? 獲取到命令返回值,檢查這個返回值是否為 0,就能判斷某個字符串是否為另一個字符串的子字符串。

注意:這裡使用管道操作符 | 來連接標準輸入,讓 grep 命令能夠查找字符串,但是使用重定向標準輸入操作符 < 並不能讓 grep 命令查找字符串。

重定向是基於文件的操作,所給的字符串會被當成文件名。舉例如下:

<code>$ grep "string" < "This is a test string." 

-bash: This is a test string.: No such file or directory
/<code>

可以看到,在重定向標準輸入操作符 < 右邊的 "This is a test string." 字符串被當成文件名,bash 提示找不到文件。

這裡不是 grep 命令報錯,而是 bash 在處理重定向的時候報錯。

查找多個文件

在 grep 的命令格式中,默認是一個匹配模式對應多個文件,而不是多個匹配模式對應一個文件。

在 PATTERN 參數後面的所有參數都會認為是文件名,可以提供多個文件名,在這些文件中統一查找同一個匹配模式。

舉例說明如下:

<code>$ grep test testfile retestfile
testfile:This is a test string.
retestfile:retestfile
/<code>

在上面的 grep test testfile retestfile 命令中,test 是 PATTERN 參數,指定匹配模式,testfile 和 retestfile 都是要查找的文件名,並不是在 retestfile 文件中查找 test 模式和 testfile 模式。

在 grep 命令中使用 bash 的星號 * 通配符時,可能就會擴展成查找多個文件的情況:

<code>$ set -x
$ grep *test* testfile

+ grep --color=auto retestfile testfile testfile
$ grep test *test*
+ grep --color=auto test retestfile testfile
retestfile:retestfile
testfile:This is a test string.
$ set +x
/<code>

剛接觸 grep 命令和 bash 的星號 * 通配符時,常見的誤區是認為 grep *test* testfile 命令會在 testfile 文件查找任意包含 test 的字符串。

但是上面的打印結果為空。打開 bash 調試信息,可以看到該命令擴展為 grep --color=auto retestfile testfile testfile,基於 grep 的命令格式,其實是在 testfile文件中查找 "retestfile" 字符串,而且會查找兩次,因為提供了兩次 testfile 文件名。

Bash 的 * 通配符沒有被引號括起來時,其擴展結果來自於當前目錄下的文件名,如果多個文件名符合所給模式,就會把多個文件名作為參數傳遞給被執行命令,導致被執行命令的參數個數發生變化,要注意這個擴展結果是否符合預期。

可以看到,grep test *test* 命令的擴展結果是 grep --color=auto test retestfile testfile,在 retestfile、testfile 這兩個文件中查找 "test" 字符串。

即,認識到 grep 命令是一個匹配模式對應多個文件,有助於理解在命令參數中使用 bash 的 * 通配符、或者其他通配符時的執行結果。

如果要查找多個匹配模式,要通過其他選項、或者正則表達式來指定。後面會具體說明。

匹配模式為空字符串時會匹配所有行

當 grep 命令的 PATTERN 參數為空字符串時,會匹配所給文件的所有行。

舉例說明如下:

<code>$ cat testfile
This is a test string.
$ grep "" testfile
This is a test string.
$ grep '' testfile
This is a test string.
/<code>

可以看到,grep "" testfile 命令和 grep '' testfile 命令都匹配了 testfile 文件的所有行。

GNU grep 的在線幫助鏈接 https://www.gnu.org/software/grep/manual/grep.html#Usage 對此進行了說明:

11. Why does the empty pattern match every input line?

The grep command searches for lines that contain strings that match a pattern. Every line contains the empty string, so an empty pattern causes grep to find a match on each line.

It is not the only such pattern: ‘^’, ‘$’, ‘.*’, and many other patterns cause grep to match every line.

To match empty lines, use the pattern ‘^$’. To match blank lines, use the pattern ‘^[[:blank:]]*$’.

即,grep 命令認為每一行都包含空字符串,所以提供的匹配模式為空字符串時,會匹配到所有行。

匹配模式寫為 '^'、'$'、'.*',也是會匹配到所有行。

如果想要匹配空行,匹配模式可以寫為 '^$',空行只包含一個行末的換行符。

如果想要匹配只包含空白字符(空格、或 tab 字符)的行,匹配模式可以寫為 ^[[:blank:]]*$。

顏色高亮匹配到的模式字符串

在 Linux 中,grep 命令默認不會顏色高亮匹配到的模式字符串。

如果想要高亮所匹配的部分,需要加上 --color=auto 或者 --color=always 選項才會顯示顏色高亮。

在一些 Linux 系統上,執行 grep 命令,沒有手動加 --color=auto 也會看到顏色高亮。

這是因為 bash 設置了 alias 別名,默認已經加上 --color=auto 選項。

具體舉例說明如下:

<code>$ alias grep
alias grep='grep --color=auto'
/<code>

可以看到,bash 設置了 grep 字符串為 grep --color=auto 命令的別名。

那麼在 bash 中執行 grep 命令,實際執行的是 grep --color=auto,所以能夠顏色高亮。

可以使用 \\grep 來指定不使用 alias 別名,執行原始的 grep 命令,就能看到沒有顏色高亮。

具體舉例說明如下:

Linux技巧:多實例介紹 grep 命令的常見用法

grep命令顏色高亮

在這個測試結果中,只有 \\grep "string" testfile 命令確實沒有加 --color=auto 選項,打印的匹配結果沒有顏色高亮。

查看 man grep 對 --color 選項、以及它的取值說明如下:

--color[=WHEN], --colour[=WHEN]

Surround the matched (non-empty) strings, matching lines, context lines, file names, line numbers, byte offsets, and separators (for fields and groups of context lines) with escape sequences to display them in color on the terminal.

WHEN is never, always, or auto.

一般來說,當指定為 always、auto 時,可以顯示顏色高亮。

當指定為 never 時,不會顯示顏色高亮。

如果沒有提供 --color 選項,默認值就是 never,不顯示顏色高亮。

注意:在非交互式 shell 中,默認不能使用 alias 別名。

由於 shell 腳本默認運行在非交互式 shell 下,當在 shell 腳本中使用 grep 命令時,不會自動在 grep 命令後面加上 --color=auto 選項,打印的匹配結果沒有顏色高亮。

在 shell 腳本中執行 grep 命令時,如果想要打印的匹配結果顯示顏色高亮,需要在 shell 腳本的 grep 命令後面主動加上 --color=auto 選項。

查看 man bash 裡面對非交互式 shell 不能使用 alias 別名的說明如下:

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt.

使用 -r 選項指定查找所給目錄、及其子目錄的所有文件

在 grep 命令的 -r 選項後面可以提供一個目錄名,指定在所給目錄、及其子目錄的所有文件中進行匹配。

查看 man grep 對 -r 選項的說明如下:

-r, --recursive

Read all files under each directory, recursively, following symbolic links only if they are on the command line. This is equivalent to the -d recurse option.

即,-r 選項指定遞歸讀取所給目錄下的所有文件,默認不處理符號鏈接文件,除非在命令行參數中提供了符號鏈接的文件名。

另外一個 -R 選項默認會處理符號鏈接文件,這裡不討論 -R 選項。

注意:-r 選項強調的是讀取目錄下的所有文件,不會匹配目錄名本身,即使目錄名符合指定模式也不會匹配。

而 grep 命令默認可以匹配目錄名本身。

具體舉例如下:

<code>$ grep "string" *
grep: string: Is a directory
testfile:This is a test string.
$ grep "string" -r .
./testfile:This is a test string.
$ grep -d skip "string" *
testfile:This is a test string.
/<code>

可以看到,grep string * 命令的打印結果裡面,有一個 string 目錄名匹配 "string" 字符串模式。

而用 grep "string" -r . 命令查找當前目錄下的所有文件,打印結果沒有匹配到 string 這個目錄名,加了 -r 選項不會再匹配目錄名。

也可以使用 -d skip 選項來指定不匹配目錄名,如 grep -d skip "string" * 命令的打印結果所示。

另外,grep "string" * 命令是由 bash 把通配符 * 擴展為當前目錄下的所有文件名,包括子目錄名自身,但不會遞歸擴展子目錄下的文件名。

而 grep "string" -r . 命令會遞歸查找子目錄下的所有文件。注意這兩者的區別。

使用 --exclude 或 --include 指定過濾特定的文件名

當使用 grep 命令搜索多個文件時,可以使用 --exclude 指定忽略不搜索特定的文件名,或者使用 --exclude 指定只搜索特定的文件名。

查看 man grep 對這兩個選項對說明如下:

--exclude=GLOB

Skip any command-line file with a name suffix that matches the pattern GLOB, using wildcard matching;

a name suffix is either the whole name, or a trailing part that starts with a non-slash character immediately after a slash (/) in the name.

A pattern can use *, ?, and [...] as wildcards, and \\ to quote a wildcard or backslash character literally.


--include=GLOB

Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).

即,使用 --exclude=GLOB 指定忽略匹配 GLOB 模式的文件名,可以使用 bash 通配符來指定符合所給模式的多個文件名。

使用 --include=GLOB 則是指定只搜索匹配 GLOB 模式的文件名。

使用 -w 選項指定全詞匹配

grep 命令默認不是全詞匹配,可以匹配到某個單詞的一部分。如果想要全詞匹配,可以加上 -w 選項。

查看 man grep 對 -w 選項的說明如下:

-w, --word-regexp

Select only those lines containing matches that form whole words. The test is that the matching substring must either be at the beginning of the line, or preceded by a non-word constituent character.

Similarly, it must be either at the end of the line or followed by a non-word constituent character. Word-constituent characters are letters, digits, and the underscore.

即,“全詞匹配”指的是所匹配單詞的開頭和末尾前後都要是不能組成單詞的字符。能夠組成單詞的字符是字母、數字、和下劃線。

具體舉例如下:

<code>$ echo -e "This is a test string.\\nThis" > testfile
$ grep "is" testfile
This is a test string.
This
$ grep -w "is" testfile
This is a test string.
/<code>

可以看到,grep "is" testfile 命令會匹配到 "This" 字符串。

而 grep -w "is" testfile 命令不會匹配到 "This" 字符串。

注意:標點符號並不是能夠組成單詞的字符,字符串後面跟著標點符號並不影響全詞匹配。

舉例如下:

<code>$ grep -w "string" testfile
This is a test string.
/<code>

可以看到,使用 -w 選項指定全詞匹配 "string" 字符串,能夠匹配到包含 "string." 字符串的這一行,單詞後面的標點符號不影響全詞匹配。

不加 -w 選項時,也可以通過正則表達式來指定全詞匹配。後面會具體說明。

使用 -n 選項指定打印所匹配行的行號

grep 命令在打印匹配行時,默認不顯示該行的行號。如果想要顯示行號,可以加上 -n 選項。

查看 man grep 對 -n 選項的說明如下:

-n, --line-number

Prefix each line of output with the 1-based line number within its input file.

即,行號的編號從數字 1 開始。具體舉例如下:

<code>$ grep -n "is" testfile
1:This is a test string.
2:This
/<code>

在匹配行前面打印的數字就是這一行的行號。

使用 -i 選項指定忽略大小寫

grep 命令在匹配時,默認會區分大小寫。例如 "TEST" 模式不能匹配到 "test" 字符串。可以使用 -i 選項來指定忽略大小寫。

查看 man grep 對 -i 選項的說明如下:

-i, --ignore-case

Ignore case distinctions in both the PATTERN and the input files.

具體舉例如下:

<code>$ grep "TEST" testfile
$ grep -i "TEST" testfile
This is a test string.
/<code>

可以看到,grep "TEST" testfile 命令沒有匹配到任何內容。

而 grep -i "TEST" testfile 命令指定匹配時忽略大小寫,可以匹配到 "test" 字符串。

使用 -v 選項指定打印不匹配的行

grep 命令默認會打印匹配的行,可以使用 -v 選項指定打印不匹配的行,也就是過濾掉匹配的行。

查看 man grep 對 -v 選項說明如下:

-v, --invert-match

Invert the sense of matching, to select non-matching lines.

具體舉例如下:

<code>$ grep -v "test" testfile
This
/<code>

可以看到,加了 -v 選項後,沒有打印出包含 "test" 模式的 "This is a test string." 這一行,而是打印出不包含 "test" 模式的 "This" 這一行。

使用 -e 選項分別指定多個模式字符串

grep 命令可以使用 -e 選項來分別指定多個模式字符串,每個模式字符串前面都要加 -e 選項。

查看 man grep 對 -e 的說明如下:

-e PATTERN, --regexp=PATTERN

Use PATTERN as the pattern. This can be used to specify multiple search patterns, or to protect a pattern beginning with a hyphen (-).

即,在 -e 選項後面的 PATTERN 參數會被當成要匹配的模式字符串,提供多個 -e 選項就能匹配多個模式字符串。

注意不要在單個 -e 選項後面直接跟多個模式字符串,否則會報錯。

如果所給的模式字符串以 - 字符開頭,grep 命令會認為是一個選項參數,導致報錯。

此時可以用 \\- 對 - 字符進行轉義,或者用 -e 選項來指定以 - 字符開頭的模式字符串。

具體舉例如下:

<code>$ grep "-test" testfile
grep: invalid option -- 't'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
$ grep -e "-test" -e "is" testfile
This is a test string.
New -test string

/<code>

可以看到,grep "-test" testfile 命令想要匹配 -test 模式字符串,但是執行報錯,grep 命令把該模式字符串前面的 -t 當成了一個選項。

而 grep -e "-test" -e "is" testfile 命令不會執行報錯,-e "-test" 選項可以正確識別是要匹配 -test 模式字符串。

-e "-test" -e "is" 這兩個選項指定匹配 -test 模式字符串或 is 模式字符串。

如果不想寫多個 -e 選項,也可以通過 -E 選項使用擴展正則表達式來匹配多個模式。後面會具體說明。

使用基本正則表達式來指定匹配模式

grep 命令可以使用 -G 選項來指定基本正則表達式(basic regular expression)的匹配模式,默認會提供這個選項,可以不用手動提供。

查看 man grep 對 -G 選項的說明如下:

-G, --basic-regexp

Interpret PATTERN as a basic regular expression (BRE). This is the default.

在 man grep 的 REGULAR EXPRESSIONS 小節,對正則表達式語法有所介紹。常見表達式說明如下:

  • 使用 ^ 匹配行首的空字符串。由於是匹配空字符串,其實就是匹配到行首,所以 ^This 表示要匹配以 "This" 字符串開頭的行。
  • 使用 $ 匹配行末的空字符串,也就是匹配到行末。例如 string$ 表示匹配以 "string" 字符串結尾的行。
  • 使用 \\< 匹配單詞開頭的空字符串。例如 \\
  • 使用 \\> 匹配單詞末尾的空字符串。例如 ing\\> 表示匹配以 "ing" 結尾的單詞。
  • 使用 \\ 來全詞匹配這兩個表達式中間的單詞。例如 \\ 表示全詞匹配 "is" 這個字符串。
  • 使用 * 匹配零個或連續多個前面的上一個字符。例如 a* 匹配空字符串、"aa" 字符串、"aaaaaa" 字符串等。
  • 使用 [] 來匹配方括號內的任意一個字符。例如 [abc] 可以匹配字符 a、字符 b、字符 c。

還有一些其他的表達式,後面用到再具體說明。

使用基本正則表達式進行匹配的一些例子說明如下:

<code>$ echo -e "This is a test string.\\nNew. This is a testString" > testfile
$ grep "^This" testfile
This is a test string.
$ grep "ing$" testfile
New. This is a testString
$ grep "\\
This is a test string.
$ grep "String\\>" testfile
New. This is a testString
$ grep "\\<test>" testfile
This is a test string.
/<test>
/<code>

可以看到,grep "^This" testfile 匹配以 "This" 開頭的行,沒有匹配 "This" 在中間的行。

grep "ing$" testfile 匹配以 "ing" 結尾的行,不會匹配 "ing." 的情況,末尾多了標點符號也不匹配。

grep "\\ 匹配包含以 "str" 開頭的單詞的行。

grep "String\\>" testfile 匹配包含以 "String" 結尾的單詞的行。

grep "\\<test>" testfile/<test> 全詞匹配包含 "test" 這個單詞的行,跟 grep -w 選項的功能相同。

POSIX 字符類

grep 命令可以在正則表達式中使用 POSIX 字符類匹配某類特殊字符。

例如在 ASCII 編碼格式下,[:alnum:] 是 A-Za-z0-9 的另一個寫法,那麼 [[:alnum:]] 相當於 [A-Za-z0-9],對應任意一個字母或數字。

注意:在 [:alnum:] 這個寫法中,兩邊的方括號 [] 是這個字符類的一部分,並不是正則表達式的 [] 表達式,要把整個內容再放到方括號 [] 裡面,寫成 [[:alnum:]] 才是有效的正則表達式。

具體舉例如下:

<code>$ grep [:alnum:] testfile
grep: character class syntax is [[:space:]], not [:space:]
$ grep [[:alnum:]] testfile
This is a test string.
New. This is a testString
/<code>

可以看到,grep [:alnum:] testfile 命令執行報錯,提示正確的語法格式是把 [:space:] 再放到一個方括號 [] 裡面。

這裡打印的 [:space:] 是一個舉例的提示,跟該命令提供的 [:alnum:] 無關。

而 grep [[:alnum:]] testfile 命令沒有執行報錯,它會匹配到各個字母、或數字。

參考 GNU grep 在線幫助手冊 https://www.gnu.org/software/grep/manual/html_node/Character-Classes-and-Bracket-Expressions.html ,對 grep 命令支持的各個 POSIX 字符類的說明如下:

Linux技巧:多實例介紹 grep 命令的常見用法

POSIX字符類

注意:雖然 [:space:] 可以匹配換行符,但是 grep 命令在讀取文件內容時,會去掉行末的換行符,所以在 grep 中用 [:space:] 匹配不到只有一個換行符的空行。

使用擴展正則表達式來指定匹配模式

上面提到,grep 命令默認支持用基本正則表達式來指定匹配模式。除此之外,可以用 -E 選項來指定使用擴展正則表達式(extended regular expression)。

查看 man grep 對 -E 選項的說明如下:

-E, --extended-regexp

Interpret PATTERN as an extended regular expression (ERE).

在 man grep 的 Basic vs Extended Regular Expressions 小節提到了基本正則表達式和擴展正則表達式的區別:

In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions ?, +, {, |, (, and ).

即,比起基本正則表達式,擴展正則表達式在使用一些元字符時,不需要用反斜線 \\ 進行轉義就能使用。

例如,在基本正則表達式中,+ 就表示加號 ‘+’ 這個字符本身,沒有什麼特殊含義,如果想要當成正則表達式元字符,需要寫成 \\+ 的形式。

而在擴展正則表達式中,+ 對應正則表達式的元字符,不用寫成 \\+ 的形式。

注意:grep 命令使用 GNU BRE 版本的基本正則表達式,GNU BRE 也支持擴展正則表達式的這些元字符,只是要用反斜線 \\ 進行轉義而已。

而 POSIX 標準定義的 BRE 不支持 ?, +, {, | 這些元字符。

對於部分元字符說明如下:

  • 使用 ? 表示匹配零個或一個前面的上一個字符,最多隻能匹配一個字符。
  • 使用 + 表示匹配一個或連續多個前面的上一個字符,至少匹配一個字符。
  • 使用 | 表示匹配在該元字符前面的模式、或者匹配在該元字符後面的模式。例如,abc|efg 表示匹配 "abc" 字符串、或者匹配 "efg" 字符串。

一般常用 grep -E 和 | 元字符來指定匹配多個模式,類似於提供多個 -e pattern 選項。

舉例說明如下:

<code>$ grep -E "test string|testString" testfile
This is a test string.

New. This is a testString
$ grep "test string\\|testString" testfile
This is a test string.
New. This is a testString
$ grep "test string|testString" testfile
/<code>

可以看到,grep -E "test string|testString" testfile 命令可以查找到包含 "test string" 字符串、或者包含 "testString" 字符串的行。

grep "test string\\|testString" testfile 命令不提供 -E 選項,使用 GNU BRE 基本正則表達式,用 \\| 對 | 元字符進行轉義,也能查找到包含 "test string" 字符串、或者包含 "testString" 字符串的行。

grep "test string|testString" testfile 命令則什麼都沒有查找到。

使用 -q 選項指定不打印任何內容

如前面說明,可以使用類似 echo "$value" | grep pattern 這樣的命令,在 value 變量值中查找 pattern 模式,並檢查 grep 命令的返回值,從而判斷 pattern 模式字符串是不是 value 變量值的子字符串。

這個命令有一個小問題是會打印匹配結果。

對於判斷是否子字符串的需求來說,我們只需要使用 $? 獲取 grep 命令返回值並進行檢查即可,並不需要看到這個匹配結果。

此時,可以使用 -q 選項指定不打印任何內容。

查看 man grep 對 -q 選項的說明如下:

-q, --quiet, --silent

Quiet; do not write anything to standard output. Exit immediately with zero status if any match is found, even if an error was detected.

即,-q 選項指定不打印任何內容到標準輸出,即使遇到錯誤也不打印,只會返回命令執行的結果,如果匹配返回 0,否則返回非 0 值。

可以用 $? 來獲取到這個返回值。

舉例說明如下:

<code>$ grep -q "test" testfile
$ echo $?
0
$ grep -q "NONE" testfile
$ echo $?
1
/<code>

可以看到,grep -q "test" testfile 命令在 testfile 文件中能查找到 "test" 字符串,但是沒有打印出匹配行, echo $? 打印為 0,說明確實能匹配。

對於查找不到 "NONE" 字符串的情況,echo $? 打印為 1。

使用 -A、-B、或 -C 選項查看匹配行前後的內容

grep 命令默認只打印包含匹配模式的行,如果想要打印這一行的前後幾行,可以使用 -A、-B、或 -C 選項。

查看 man grep 對這幾個選項的說明如下:

-A NUM, --after-context=NUM

Print NUM lines of trailing context after matching lines. Places a line containing a group separator (--) between contiguous groups of matches.

-B NUM, --before-context=NUM

Print NUM lines of leading context before matching lines. Places a line containing a group separator (--) between contiguous groups of matches.

-C NUM, -NUM, --context=NUM

Print NUM lines of output context. Places a line containing a group separator (--) between contiguous groups of matches.

即,-A NUM 指定打印匹配行後面的 NUM 行。

-B NUM 指定打印匹配行前面的 NUM 行。

-C NUM 指定打印匹配行前後的 NUM 行,這個選項可以簡寫為 -NUM。

對於這三個選項來說,每一個匹配行會打印出多行內容,在不同匹配內容塊之間會在打印一個只包含 -- 的行來分隔開。

具體舉例說明如下:

<code>$ echo -e "1\\n2\\n3\\n4\\n5\\n11\\n22\\n33\\n44\\n55" > testfile
$ grep 3 -A 1 testfile
3
4
--
33
44
$ grep 3 -B 1 testfile
2
3
--

22
33
$ grep 3 -C 1 testfile
2
3
4
--
22
33
44
/<code>

在這個打印結果中,-- 這一行並不是 testfile 文件自身的內容,而是 grep 命令打印的分割線。

注意:如果在匹配行的前後內容中包含另一個匹配行,那麼它們會連在一起打印,並不會重複打印同一個匹配行。

如下面的例子所示:

<code>$ echo -e "1\\n2\\n3\\n33\\n4\\n5" > testfile
$ grep 3 -B 2 testfile
1
2
3
33
/<code>

可以看到,匹配到 “3” 這一行時,它上面兩行是 “2”、“1” 這兩行,打印了這兩行。

匹配到 “33” 這一行時,它上面兩行是 “3”、“2” 這兩行,但是並沒有分隔開來打印這兩行,這兩個匹配行連在一起打印。

即,使用 -A、-B、或 -C 選項時,不會出現同一個匹配行被打印兩次的情況,相鄰匹配行前後內容的同一行也不會被打印兩次。

grep 命令對這些情況都進行了優化。

使用 -l 選項只打印文件名,不打印匹配的行內容

當在多個文件中進行查找時,grep 命令會先打印文件名,隨後再打印匹配的行內容。如果只想打印文件名,不打印匹配的行內容,可以加上 -l 選項。

查看 man grep 對 -l 選項的說明如下:

-l, --files-with-matches

Suppress normal output; instead print the name of each input file from which output would normally have been printed. The scanning will stop on the first match.

例如,我們可能想要查看某個變量出現在哪些文件中,如果打印匹配的行內容,可能會有很多輸出,不方便查看文件名,就可以加上 -l 選項來指定只打印文件名。

舉例如下:

<code>$ grep Fexecute -l -r ./
./src/kwsearch.c
./src/grep.c
./src/search.h
/<code>

基於這個打印結果,可以清楚地看到 Fexecute 變量在上面三個文件中出現過。

結合 find、xargs 命令一起使用

在 Linux 中,可以使用 find 命令來查找包含特定名稱的文件,然後用 xargs 命令把這些文件名傳給 grep 命令來統一查找特定的模式。

例如,下面命令會查找當前目錄下所有後綴名為 .c 的文件,然後在這些文件中查找 "main" 字符串:

<code>$ find . -name "*.c" | xargs grep "main"
/<code>

注意:上面的 xargs 命令必須提供,否則不會查找文件內容。如果寫成 find . -name "*.c" | grep "main",那麼是在 find 命令打印的文件名中查找 "main" 字符串,而不是在這些文件名對應的文件內容中進行查找。

另外,xargs 命令調用 grep 時,沒有繼承 bash 的 alias 別名,所以打印結果沒有顏色高亮。如果想要顯示顏色高亮,需要寫為 xargs grep --color=auto 的形式。


分享到:


相關文章: