grep 命令详解

1. grep 简介

grep 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。通常grep有三种版本grepegrep(等同于grep -E)和fgrep。egrep为扩展的grep,fgrep则为快速grep(使用固定的字符串来对文本进行搜索,不支持正则表达式的引用,但是查询极为快速)。grep是Linux文本处理三剑客之一,与 sed、awk 相比 grep 的使用或许简单一些,但是 grep 的搜索能力非常强大,值得学习一下。

【sed 命令详解】
https://blog.csdn.net/qq_42226855/article/details/134792377

【awk 命令详解】
https://blog.csdn.net/qq_42226855/article/details/135089290

2. grep 基本语法

grep 命令的基本语法是:

grep [options] pattern [input_file_names]

这个命令的各个部分如下:

options:这些是可选的命令行选项,用于控制 grep 命令的行为。一些常见的选项包括(此处仅列举了部分选项):
-c: 只输出匹配行的数量,不显示实际的匹配行。
-i: 忽略大小写进行匹配。
-v: 反向选择,即输出不包含指定模式的行。
-n: 在输出的每一行前加上其在文件中的行号。
-l: 只列出包含匹配模式的文件名,而不是显示匹配的内容。
-r 或 -R: 递归地搜索目录及其子目录中的文件。

pattern:这是要搜索的文本模式或正则表达式。如果未使用 -e 或 -f 选项,那么 pattern 就会被直接当作搜索模式。

input_file_names:这些是要搜索的输入文件名。可以指定一个或多个文件名,也可以使用通配符(如 *)来匹配多个文件。如果不指定任何文件名,grep 会从标准输入读取数据。

以下是一些示例(grep 总是对输入的每个单行进行匹配):

搜索单个文件中包含 “example” 的行:

grep "example" file.txt

使用 -i 选项忽略大小写,并搜索多个文件:

grep -i "example" file1.txt file2.txt

使用 -r 选项递归搜索目录及其子目录中的所有文件:

grep -r "example" directory/

使用 -c 选项只输出匹配行的数量:

grep -c "example" file.txt

2.1 命令行选项 [options]

grep 命令行选项可以分为几个类别:

POSIX 标准选项:这些是按照 POSIX(Portable Operating System Interface)标准定义的选项,旨在确保在不同操作系统和实现之间的一致性。例如:
-c: 只输出匹配行的数量。
-i: 忽略大小写进行匹配。
-l: 列出包含匹配模式的文件名。
-n: 在输出的每一行前加上其在文件中的行号。
-v: 反向选择,即输出不包含指定模式的行。

GNU 扩展选项:GNU 版本的 grep 提供了一些额外的、非 POSIX 标准的选项,以增强功能和灵活性。例如:
-E: 使用扩展正则表达式(ERE)而不是基本正则表达式(BRE)。
-F: 将模式视为固定字符串,而非正则表达式。
-o: 只输出匹配的部分,而不是整个行。
-P: 使用 Perl 兼容的正则表达式(PCRE)。

长选项:除了短选项(如 -c、-i 等),许多命令也支持长选项,通常是为了提高可读性和清晰度。例如,-c 的长选项形式是 --count,-i 的长选项形式是 --ignore-case。

移植性和兼容性选项:为了方便在不同系统间移植脚本或与旧版本的工具兼容,grep 可能会提供一些特定的选项或行为。例如,传统的 grep 实现可能不支持某些 GNU 扩展选项,因此在编写跨平台脚本时需要考虑到这一点。

特殊情况和设计考虑:某些选项的设计可能还考虑到了特殊用例或情况。例如,-q 参数(quiet mode)在 GNU grep 中用于静默搜索,只检查是否存在匹配而不输出任何内容。而在某些传统 grep 实现中,-s 参数可能会有类似的行为,但在 POSIX 规范中,-s 参数实际上表示“silent”模式,用于处理二进制文件而不产生错误。

2.1.1 获取常规程序信息

grep 命令提供了以下两个选项来获取常规程序信息:

--help

功能:这个选项用于打印命令行帮助信息,包括可用的选项、参数和简要说明。
用途:当你不确定如何使用 grep 命令或者需要查看某个选项的具体含义时,可以使用这个选项获取帮助。

[root@ufo666 ~]# grep --help
Usage: grep [OPTION]... PATTERN [FILE]...
Search for PATTERN in each FILE or standard input.
PATTERN is, by default, a basic regular expression (BRE).
Example: grep -i 'hello world' menu.h main.c

Regexp selection and interpretation:
  -E, --extended-regexp     PATTERN is an extended regular expression (ERE)
  -F, --fixed-strings       PATTERN is a set of newline-separated fixed strings
  -G, --basic-regexp        PATTERN is a basic regular expression (BRE)
  -P, --perl-regexp         PATTERN is a Perl regular expression
  -e, --regexp=PATTERN      use PATTERN for matching
  ...

-V 或 --version

功能:这两个选项用于打印 grep 的版本信息。通常,输出会包含 grep 的版本号、版权信息以及可能的 bug 报告地址。
用途:当你需要了解正在使用的 grep 版本,或者在报告 bug 时需要提供版本信息时,可以使用这个选项。

grep -Vgrep --version

[root@ufo666 ~]# grep -V
grep (GNU grep) 2.16
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

2.1.2 匹配控制选项

以下是 grep 命令中匹配控制选项:

-e pattern 或 --regexp=pattern

功能:指定一个正则表达式模式用于搜索。可以使用多个 -e 选项来指定多个查询规则。
示例:grep命令会在file.txt文件中搜索与任一模式匹配的行,并将其打印出来。

grep -e 'pattern1' -e 'pattern2' file.txt

注意:如果在命令行中直接输入模式,而不使用 -e 选项,那么 grep 将默认使用该模式作为搜索规则。

-f file 或 --file=file

功能:从指定的文件中读取匹配规则,每行作为一个规则。空文件不包含任何规则,因此不会匹配任何内容。

grep -f rules.txt input.txt

-i, -y, 或 --ignore-case

功能:在搜索过程中忽略大小写差异,即进行不区分大小写的匹配。

grep -i 'PATTERN' file.txt

-v 或 --invert-match

功能:获取未匹配的行,即输出不包含指定模式的行。
示例:在file.txt文件中搜索不包含pattern的行,并将其打印出来。

grep -v 'pattern' file.txt

-w 或 --word-regexp

功能:获取包含整个单词的匹配行,单词由字母、数字和下划线组成,并且两边不能是这些字符。

grep -w 'word' file.txt

[root@ufo666 ~]# echo -e "AAA\nAAAB" |grep -w 'AAA'
AAA

这里的“整个单词”指的是符合以下条件的单词:

  • 单词由字母、数字和下划线组成。
  • 单词两边不能是字母、数字和下划线。

换句话说,-w选项会确保匹配的单词不是其他单词的一部分,而是作为一个完整的单词存在。

-x 或 --line-regexp

功能:要求整行匹配,即只有当整个行与指定模式完全匹配时才会输出该行。

grep -x 'exact line' file.txt

[root@ufo666 ~]# echo -e "AAA B\nAAAB\nAAA" |grep -x 'AAA'
AAA

2.1.3 常规输出控制

以下是 grep 命令中常规输出控制选项:

-c 或 --count

功能:输出文件中匹配行的数量,而非匹配的内容。与 -v 参数一起使用,可以统计未匹配的行数量。
示例:统计当前目录下所有 .txt 文件中包含 ‘example’ 的行数。

grep -rc 'example' *.txt

[root@ufo666 ~]# grep -rc 'word' *.txt
666.txt:0
data.txt:0
file1.txt:3
file.txt:3
output.txt:0
[root@ufo666 ~]# echo -e "AAA B\nAAAB\nAAA" |grep -c 'AAA'
3
[root@ufo666 ~]# echo -e "AAA B\nAAAB\nAAA" |grep -vc 'AAA'
0

统计当前目录及其子目录中不包含 ‘example’ 的所有 .txt 文件,并输出文件名。

grep -Lr 'example' ./*.txt

# 缺少了 file.txt、file1.txt 文件
[root@ufo666 ~]# grep -Lr 'word' ./*.txt
./666.txt
./data.txt
./output.txt

--color[=WHEN] 或 --colour[=WHEN]

功能:通过环境变量 GREP_COLORS 定义高亮颜色来突出显示匹配项。默认值为 ‘ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36’。WHEN 参数可设置为 never, always 或 auto,分别表示从不、始终和自动(仅在输出到终端时)启用颜色。

在grep命令中,可以通过环境变量 GREP_COLORS 来定义高亮颜色以突出显示匹配项。下面是环境变量 GREP_COLORS 的几个字段的默认值和含义的示例:

  • ms字段(match start)的默认值是01;31,表示红色加粗。它用于突出显示匹配的起始位置。

  • mc字段(match content)的默认值是01;31,表示红色加粗。它用于突出显示匹配的文本。

  • sl字段是选项从左边显示的颜色的字段。默认值为空,表示没有颜色。如果设置为01;34,表示蓝色加粗。

  • cx字段是选项从右边显示的颜色的字段。默认值为空,表示没有颜色。如果设置为01;34,表示蓝色加粗。

  • fn字段是文件名的颜色的字段。默认值是35,表示紫色。如果设置为32,表示绿色。

  • ln字段是行号的颜色的字段。默认值是32,表示绿色。如果设置为31,表示红色。

  • bn字段是列号的颜色的字段。默认值是32,表示绿色。如果设置为31,表示红色。

  • se字段是分隔符的颜色的字段。默认值是36,表示青色。如果设置为35,表示紫色。

示例:在搜索结果中以红色高亮显示匹配项,并始终启用颜色。

GREP_COLORS='ms=01;31' grep --color=always 'pattern' file.txt
或
export GREP_COLORS='ms=01;34:mc=01;34:sl=01;34:cx=01;34:fn=32:ln=31:bn=31:se=35'

自动根据输出设备的默认值启用或禁用颜色。

grep --color=auto 'pattern' file.txt

-L 或 --files-without-match

功能:仅输出未匹配的文件名。
示例:查找当前目录及其子目录中不包含 ‘example’ 的所有 .txt 文件。

grep -Lr 'example' ./*.txt

-l 或 --files-with-matches

功能:仅输出包含匹配内容的文件名。
示例:查找当前目录及其子目录中包含 ‘example’ 的所有 .txt 文件。

grep -lr 'example' ./*.txt

[root@ufo666 ~]# grep -rc 'AA' *.txt
666.txt:0
data.txt:0
file1.txt:0
file.txt:0
output.txt:1

[root@ufo666 ~]# grep -rcl 'AA' *.txt
output.txt

-m num 或 --max-count=num

功能:匹配 num 行后停止读取文件。当与 -c 或 --count 一起使用时,输出的匹配行计数不会大于 num。与 -v 或 --invert-match 一起使用时,会输出 num 次匹配过程中的未匹配项。
示例:在每个文件中最多显示前5个包含 ‘example’ 的行。

grep -m 5 'example' *.txt
[root@ufo666 ~]# cat file.txt
666 
This is a word
This is a word
This is a word
Another word here
A sentence without the wordss

[root@ufo666 ~]# grep -m 1  'is' file.txt
This is a word
# 一行出现多次时,只记录一次匹配
[root@ufo666 ~]# grep -m 2  'is' file.txt
This is a word
This is a word
# 取-v时,-m 选项不再限制,只会展示未匹配到的行
[root@ufo666 ~]# grep -m 2 -v 'is' file.txt
Another word here
A sentence without the wordss

-o 或 --only-matching

功能:打印行中匹配的内容部分(非空)。
示例:只显示包含 ‘example’ 的部分。

grep -o 'example' file.txt

# 一行匹配到n次,就输出n次。
[root@ufo666 ~]# grep -m 1 -o 'is' file.txt
is
is

-q 或 --quiet 或 --silent

功能:不进行标准输出。如果发现匹配项,则立即退出,并返回状态码0。即使存在执行错误,也不会进行输出。
示例:检查文件中是否包含 ‘example’,并根据结果执行不同的操作。它会返回一个退出状态,表示搜索是否成功。如果找到了至少一个匹配项,那么退出状态为0,这表示搜索成功,否则失败。

if grep -q 'example' file.txt; then
    echo "Pattern found in file.txt"
else
    echo "Pattern not found in file.txt"
fi

-s 或 --no-messages

功能:针对读取错误不进行标准错误输出。当搜索二进制文件或其他非文本文件时,可能会出现读取错误。
示例:在搜索当前目录及其子目录中的所有文件时,忽略二进制文件的读取错误。

grep -rs 'example' . --binary-files=without-match

# 假设我们有一个名为binary_file.bin的二进制文件,内容如下:
0101010101010101
# 如果我们尝试在这个二进制文件上执行grep搜索,而没有使用--binary-files=without-match选项,会出现以下错误消息:
grep: binary_file.bin: Binary file matches

2.1.4 输出行前缀控制

以下是 grep 输出行前缀控制选项:

-b 或 --byte-offset

功能:这个选项会在每行匹配内容的前面打印字符偏移量。这对于查看文件中的具体位置非常有用。 示例:

grep -b "example" file.txt

# 显示文件中的隐藏字符,偏移量包含隐藏换行符
[root@ufo666 ~]# cat -A file.txt 
666$                   	-- 4个
This is a word$        	-- 15个
This is a word$			-- 15个
This is a word$			-- 15个
Another word here$
A sentence without the wordss$
[root@ufo666 ~]# 
[root@ufo666 ~]# grep -m 2 -b '6' file.txt
0:666
[root@ufo666 ~]# grep -m 2 -b 'T' file.txt
4:This is a word
19:This is a word		-- 15+4 个
[root@ufo666 ~]# grep -m 3 -b 'T' file.txt
4:This is a word
19:This is a word		-- 15+4 个
34:This is a word		-- 15+15+4 个

-H 或 --with-filename:

功能:当搜索多个文件时,这个选项会确保在每个匹配行的前面都打印出文件名。这是grep的默认行为,但在某些情况下,如果你使用了其他可能改变此行为的选项(如-h),你可以使用-H来明确要求显示文件名。 示例:

grep -H "example" file1.txt file2.txt

# 默认输出带文件名
[root@ufo666 ~]# grep 'word' *.txt
file1.txt:This is a word
file1.txt:Another word here
file1.txt:A sentence without the wordss
file.txt:This is a word
file.txt:This is a word
file.txt:This is a word

# 明确要求带文件名
[root@ufo666 ~]# grep -H 'word' *.txt
file1.txt:This is a word
file1.txt:Another word here
file1.txt:A sentence without the wordss
file.txt:This is a word
file.txt:This is a word
file.txt:This is a word

# 明确不带文件名
[root@ufo666 ~]# grep -h 'word' *.txt
This is a word
Another word here
A sentence without the wordss
This is a word
This is a word
This is a word


-h 或 --no-filename

功能:这个选项在输出匹配行时不包含文件名。这对于查询单个文件或者不需要知道文件名的情况很有用。例如:

grep -h "pattern" file.txt

--label=LABEL

功能:这个选项在输出匹配行时添加指定的标签。这对于区分不同输入源或者标记特定数据流很有用。例如:

gzip -cd foo.gz | grep --label=foo -H "something"

# 只输出了 file1.txt 文件中的匹配情况
[root@ufo666 ~]# grep --label='file1.txt' 'word' file.txt file1.txt
file1.txt:This is a word
file1.txt:Another word here
file1.txt:A sentence without the wordss

注意,--label=LABEL选项是GNU grep特有的,并不是标准的grep命令选项。因此,该选项在其他grep实现中可能不可用。

-n 或 --line-number

功能:这个选项在输出匹配行时显示其在文件中的行号。这对于定位问题或者理解代码结构非常有帮助。例如:

grep -n "pattern" file.txt

[root@ufo666 ~]# grep -n 'word' file.txt
2:This is a word
3:This is a word
4:This is a word
5:Another word here
6:A sentence without the wordss

-T 或 --initial-tab

功能:这个选项在输出匹配行之前添加一个制表符(tab)作为对齐。这可以使得输出更加整齐和易读。例如:

grep -T "pattern" file.txt

请注意,这些选项可以根据需要组合使用。例如,如果你想在不显示文件名的同时显示匹配行的行号,并且对齐输出,你可以这样使用:

grep -hTn "pattern" file.txt

[root@ufo666 ~]# grep -hTn 'word' file.txt
   2   :This is a word
   3   :This is a word
   4   :This is a word
   5   :Another word here
   6   :A sentence without the wordss

-u 或 --unix-byte-offsets

功能:这个选项使得grep在报告字节偏移量时,将文件视为Unix风格的文本文件,即忽略文件中的回车(CR)字符。这对于在不同操作系统之间进行一致的文本处理非常有用。例如:

grep -u -b "pattern" file.txt

了解,Windows系统上的文本文件使用CRLF(回车换行)作为换行符,表示为"\r\n"。 在Windows上,每行末尾会有回车符(\r)和换行符(\n)的组合,用于表示换行。而在Unix/Linux系统上,文本文件使用LF(换行符)作为换行符,表示为"\n" 即 “$”。在这些系统上,每行末尾只有一个换行符。当Linux系统遇到Windows风格的文本文件时,它会将回车符(CR)视为普通字符,并将其显示为^M 。

-Z 或 --null

功能:这个选项使得grep在输出文件名时使用ASCII NUL字符(\0)代替通常的换行符。这在需要将grep的输出传递给其他命令(如 xargs )并且文件名中可能包含特殊字符或空格时非常有用。例如:

find . -type f -print0 | grep -Z "pattern"

# .:表示当前目录。这是 find 命令的起始点,表示从当前目录开始搜索。
# -type f:这是一个选项,用于指定搜索的对象类型。-type f 表示只搜索普通文件。
# -print0:这是一个选项,用于输出搜索结果。 -print0 告诉 find 命令以 ASCII NUL 字符(\0)作为分隔符来输出文件名,而不是使用换行符

# grep -Z "pattern" 的输出结果如下:
file 1.txt\0
file 2.txt\0

在这个例子中,find命令使用-print0选项以NUL字符分隔文件名,然后grep使用-Z选项接受这种格式的输入。

请注意,输出结果中不会显示 ASCII NUL 字符(\0),但实际上它们作为分隔符存在,因此可以正确处理包含特殊字符或空格的文件名。

这些选项可以根据需要单独或组合使用。例如,如果你想在报告Unix风格的字节偏移量的同时使用NULL字符分隔文件名,你可以这样使用:

grep -uZ -b "pattern" file.txt

但是请注意,-Z或–null选项主要影响文件名的输出,而-u或–unix-byte-offsets选项影响的是匹配行的字节偏移量计算方式。这两个选项在功能上并不直接相关。

2.1.5 上下文控制

以下是 grep 上下文控制选项:

-A num 或 --after-context=num

功能:这个选项使得grep在输出匹配行之后再打印num行。num不包含匹配行本身。例如:

grep -A 1 "pattern" file.txt

[root@ufo666 ~]# grep -A 1  'is' file.txt 
This is a word
This is a word
This is a word       -- 匹配的行
Another word here    -- 再打印1行

-B num 或 --before-context=num

功能:这个选项使得grep在输出匹配行之前再打印num行。num不包含匹配行本身。例如:

grep -B 1 "pattern" file.txt

[root@ufo666 ~]# grep -B 1  'here' file.txt 
This is a word          -- 再打印1行
Another word here		-- 匹配的行

-C num 或 --context=num

功能:这个选项使得grep在输出匹配行前后各打印num行。num不包含匹配行本身。例如:

grep -C 1 "pattern" file.txt

[root@ufo666 ~]# grep -C 1  'here' file.txt 
This is a word					-- 之前再打印1行
Another word here				-- 匹配的行
A sentence without the wordss	-- 之后再打印1行

--group-separator=string

功能:这个选项允许你在使用-A、-B或-C参数时,自定义分隔匹配上下文的字符串,默认是"--"。例如:

grep -C 1 --group-separator="***" "pattern" file.txt

# 多次行匹配时,输出的结果用 *** 分割
[root@ufo666 ~]# grep -C 1 --group-separator='***'  'here' file.txt 
This is a word
Another word here
A sentence without the wordss
***
This is a word
Another word here
A sentence without the wordss

--no-group-separator

功能:这个选项使得grep在输出匹配行的上下文时不使用任何分隔符。例如:

# 明确指定不使用任何分隔符,在每次匹配输出结果之间
grep -C 1 --no-group-separator "pattern" file.txt

这将在匹配行与其上下文之间不使用任何分隔符。

2.1.6 文件和目录的选择

以下是 grep 文件和目录相关选项:

-a 或 --text

这个选项使得grep将所有文件(包括二进制文件)视为文本文件进行处理。等效于--binary-files=text。例如:

grep -a "pattern" file.bin

在默认情况下,grep会识别出二进制文件并避免尝试解析它们的内容,以防止输出乱码或者由于二进制数据中的特殊字符导致的错误。但是,当使用-a选项时,grep会忽略文件的类型,强制将其内容作为文本进行处理。

# -a选项强制grep将二进制文件视为文本文件处理。
# -P选项启用Perl兼容正则表达式(PCRE),这样我们可以使用\xHH形式来表示十六进制字节。
grep -a -P "\x48\x65\x6c\x6c\x6f" binary_file.bin

--binary-files=type

这个选项允许你指定如何处理二进制文件。例如:

  • binary(默认):如果二进制文件与模式不匹配,grep会给出提示。
  • without-match:不匹配的二进制文件将被忽略,等效于使用-I参数。
  • text:grep会尝试将二进制文件作为文本文件处理,但可能会输出不友好的内容,因为二进制数据中的某些字节可能在ASCII字符集中没有对应的含义。
grep --binary-files=without-match "pattern" *

-D action 或 --devices=action

这个选项允许你指定如何处理设备、套接字或特殊文件。例如:

  • read(默认):如果不使用-R或-r选项,grep会尝试读取设备、套接字或特殊文件的内容。
  • skip:grep会跳过这些文件,不进行任何处理。
grep -D skip "pattern" /dev/sda

根据需求,可以选择默认的行为(尝试读取内容),或者跳过这些文件以避免可能的错误或不必要的操作。在处理可能包含特殊文件的目录时,使用skip动作可以提高grep的稳定性和效率。

-d action 或 --directories=action

这个选项允许你指定如何处理目录。例如:

  • read(默认):grep会将目录视为常规文件处理,这在某些操作系统或文件系统上可能会导致错误。
  • skip:grep会跳过这些目录,不搜索其中的文件。
  • recurse:grep会递归地搜索目录中的文件,等效于使用-r或-R选项。
[root@ufo666 ~]# grep "mysql" mysql-8.0.35
grep: mysql-8.0.35: Is a directory
[root@ufo666 ~]# grep -d read "mysql" mysql-8.0.35
grep: mysql-8.0.35: Is a directory
[root@ufo666 ~]# 
[root@ufo666 ~]# grep -d skip "mysql" mysql-8.0.35
[root@ufo666 ~]# 

--exclude=glob

这个选项允许你跳过与glob模式匹配的文件名。glob模式可以包含通配符*、?、[…]等,并可以使用\进行转义。(可以匹配很多文件或所有文件,但是又同时排除一些文件)例如:

grep --exclude="*.log" "pattern" *

--exclude-from=file

这个选项允许你通过一个文件指定多个要排除的glob模式。例如:

grep --exclude-from=excludes.txt "pattern" *

--exclude-dir=dir

这个选项在递归搜索时允许你排除与dir匹配的目录。(递归搜索的同时,可以排除一些目录)例如:

grep --exclude-dir=".git" -r "pattern" .

-I

这个选项使得grep在处理二进制文件时不进行匹配,等效于--binary-files=without-match。(不进行二进制文件)例如:

grep -I "pattern" *

--include=glob

这个选项只处理与glob模式匹配的文件,规则与--exclude相反。(匹配一个范围内的部分文件)例如:

grep --include="*.txt" "pattern" *

-r 或 --recursive

这个选项使得grep递归地搜索指定目录及其子目录中的文件,并进行匹配。(匹配一个指定目录)等效于–directories=recurse。但是,这个选项不会跟随符号链接进入其他目录,也不会处理符号链接指向的文件。例如:

grep -r "pattern" directory/

-R 或 --dereferencerecursive

这个选项与-r类似,也使得grep递归地搜索指定目录及其子目录中的文件,并进行匹配。但是,这个选项会跟随符号链接进入其他目录,并处理符号链接指向的文件。例如:

grep -R "pattern" directory/

简而言之,-r或--recursive选项在递归搜索时不处理符号链接指向的目录或文件,而-R或--dereferencerecursive选项则会跟随符号链接并处理它们指向的目录或文件。

2.1.7 其他选项

--line-buffered

这个选项使得grep在输出时使用行缓冲,这意味着每匹配到一行就会立即刷新输出。这可能会导致性能问题,但可以避免输出内容的混合或混乱(一般不使用)。例如:

grep --line-buffered "pattern" file.txt

--mmap

这个选项已经被放弃使用,不再推荐。它曾经用于尝试通过内存映射文件来提高搜索性能,但现在grep默认的行为已经足够高效。

-U 或 --binary

这个选项告诉grep以二进制方式处理输入文件。例如:

  • 在MS-DOS和Windows平台上的文件,默认情况下,grep会尝试识别文件是文本还是二进制,并根据–binary-files选项来决定如何处理它们。如果grep认为文件是文本,它会去除文件原始内容中的CR字符,以确保^和$等锚定符号能够正常工作。

  • 然而,这种默认行为可能会导致问题,特别是在处理以CR/LF结尾的文本文件时。某些正则表达式可能由于行尾的CR字符被去除而无法正确匹配。使用-U或--binary选项,grep会以二进制方式处理输入文件,不对文件内容进行任何特定于文本的处理。

grep -U "pattern" file.bin

-u 或 --unix-byte-offsets 与 -U 或 --binary 的区别

  • -u--unix-byte-offsets:这个选项告诉grep在输出中使用Unix风格的字节偏移量。这意味着偏移量不会计入文件中的CR字符(回车,\r)。这个选项主要在处理从MS-DOS或Windows系统迁移过来的文件时有用,因为在这些系统中,行尾通常是CRLF(回车和换行)组合,而在Unix系统中,行尾通常是LF(换行)。

  • -U--binary:这个选项告诉grep以二进制方式处理输入文件。默认情况下,在MS-DOS和Windows平台上,grep会根据--binary-files选项来判断文件是文本还是二进制。如果grep认为文件是文本,它会去除文件原始内容中的CR字符(以确保^和$正常工作)。但是,如果文本文件行以CR/LF结尾,这可能导致某些正则表达式匹配失败。使用-U选项,grep会以二进制方式处理输入文件,不对文件内容进行任何特定于文本的处理。

所以,-u--unix-byte-offsets影响的是grep输出中显示的字节偏移量的计算方式,而-U--binary影响的是grep如何解析和处理输入文件的内容。

-z 或 --null-data

这个选项告诉grep将输入内容视为由ASCII NUL字符(\0)分隔的行集合,而不是依赖于换行符。这样可以确保在处理包含特殊字符或者合并多个文件内容时,grep能够正确地识别和匹配行。例如:

grep -z "pattern" file1.txt file2.txt

在这个例子中,grep会将file1.txt和file2.txt的内容视为一个由NUL字符分隔的行集合,并搜索其中包含"pattern"的行。


-z 或 --null-data 与 -Z 或 --null 的区别

  • -z--null-data:这个选项告诉grep将输入内容视为由ASCII NUL字符(\0)分隔的行集合。这在处理包含不可见字符(如换行符)的文件或者需要将多个文件的内容合并为一个流的情况非常有用。

  • -Z--null:这个选项的作用是在输出匹配的行时,在每行的末尾添加一个NUL字符,而不是默认的换行符。这在与其他工具(如xargs)配合使用时非常有用,因为这些工具通常可以处理以NUL字符分隔的输入。

所以,-z--null-data影响的是grep如何解析输入数据,而-Z--null影响的是grep输出的结果格式。

2.2 环境变量:

grep命令本身并没有特定的环境变量。然而,它可能受到一些通用环境变量的影响,例如:

LC_ALL、LC_CTYPE、LANG: 这些环境变量影响文本的字符分类和排序规则,从而可能影响grep的行为,特别是在处理多语言或特殊字符时。

GREP_OPTIONS: 这个环境变量在旧版本的grep中被用来设置默认的grep选项。然而,由于安全原因,现代版本的grep(如GNU grep 2.22及更高版本)已经废弃了这个环境变量,建议直接在命令行中指定选项。

环境变量LC_ALL、LC_CTYPE 和 LANG 默认值的设定取决于你的操作系统和系统的区域设置。这些环境变量用于定义locale(本地化),影响文本的字符分类、排序规则、日期和时间格式、货币符号等。

以下是一些示例:

默认值:在许多Linux系统中,如果你没有明确设置这些环境变量,它们可能会继承系统的默认值。例如:

echo $LANG
# 输出可能类似:en_US.UTF-8 或者 C

echo $LC_ALL
# 如果未显式设置,可能为空

echo $LC_CTYPE
# 如果未显式设置,可能与$LANG相同或者为空

设置变量:如果你想改变这些环境变量的值,你可以在shell配置文件中(如.bashrc或.bash_profile)进行设置,然后重新加载配置文件或打开一个新的shell会话:

export LANG=fr_FR.UTF-8
export LC_ALL=fr_FR.UTF-8
export LC_CTYPE=fr_FR.UTF-8

在这个例子中,我们设置了这些环境变量为法语(法国)的UTF-8编码。这将影响grep以及其他命令如何处理文本,包括字符分类、排序和特殊字符。

对于grep来说,这些环境变量的影响主要体现在如何识别和处理文本中的字符。例如,如果你正在搜索包含某些特殊字符或多语言文本的文件,正确的locale设置可以确保grep能够正确地匹配和显示这些字符。

2.3 退出状态:

grep命令的退出状态表示其执行结果,通常有以下几种情况:

  • 0 (成功):当grep找到匹配的模式时,它会返回退出状态0,表示命令执行成功。
  • 1 (没有匹配):当grep在输入中找不到匹配的模式时,它会返回退出状态1,表示命令执行失败(在这种情况下,失败意味着没有找到匹配)。
  • 2 (错误):如果grep遇到错误,如无法打开文件、无效的选项或正则表达式错误等,它会返回退出状态2。

在Shell脚本中,可以使用特殊变量$?来获取上一条命令(在这里是grep)的退出状态:

bash
grep "pattern" file.txt
exit_status=$?
if [ $exit_status -eq 0 ]; then
    echo "Pattern found."
elif [ $exit_status -eq 1 ]; then
    echo "Pattern not found."
else
    echo "An error occurred."
fi

请注意,不同的grep实现可能会有不同的退出状态代码约定,但上述情况适用于大多数Unix和Linux系统中的grep(包括GNU grep)。

2.4 grep 匹配规则

以下是 grep命令的匹配规则相关选项。

1.默认匹配规则

如果没有指定任何匹配规则选项(如-G-E-F-P),grep 默认使用基本正则表达式(BRE)进行匹配。

示例:

grep "pattern" file.txt

这将搜索file.txt中的包含"pattern"的行。

2.-G--basic-regexp

这是默认的匹配规则,表示使用 基本正则表达式(BRE) 进行匹配。

示例:

grep -G "patt?rn" file.txt

这将搜索file.txt中的包含"patt?rn"(其中 “?” 代表单个字符)的行。

3.-E--extended-regexp

使用 扩展正则表达式(ERE) 进行匹配。扩展正则表达式支持更多的元字符和更灵活的语法。

示例:

grep -E "patt[ern]" file.txt

这将搜索file.txt中的包含"patt[ern]"(其中 “[” 和 “]” 定义了一个字符类)的行。

4.-F--fixed-strings

将匹配规则视为一个固定字符串列表,不进行正则表达式匹配,在搜索大文件时效率非常高

示例:

grep -F "pattern" file.txt

这将搜索file.txt中的包含精确字符串"pattern"的行。

5.-P--perl-regexp

使用Perl兼容的正则表达式(PCRE)进行匹配。这个选项提供了更多高级的正则表达式功能。

示例:

grep -P "(?i)pattern" file.txt

这将搜索file.txt中的包含"pattern"(忽略大小写)的行,使用了Perl正则表达式的"(?i)"标志来启用忽略大小写的功能。

6.egrepfgrep

这两个程序分别等效于grep -Egrep -F

示例:

egrep "patt[ern]" file.txt

fgrep "pattern" file.txt

比较惊喜的是:当匹配文件比较大时,fgrep 执行效率非常高。例如,50M 的文件fgrep 命令不到 1 秒,grep 则需要 10 多分钟。

7.关于输入文件和递归选项

  • 如果输入文件为-,表示使用标准输入作为输入内容。
  • 如果未指定输入文件且命令行中有其他参数,那么这些参数被视为要搜索的标准输入内容。
  • 如果指定了递归选项(如-r-R),grep会在指定的目录及其子目录中递归搜索匹配的文件。
  • 如果未指定输入文件且没有递归选项,grep会搜索当前工作目录(.)中的文件。如果同时指定了多个文件,grep会搜索所有指定的文件。

3. 正则表达式

正则表达式是一种强大的工具,用于描述和匹配字符模式。它类似于数学公式,通过使用各种运算符、元字符和构造规则来组合简单的表达式,形成复杂的匹配规则。

grep命令支持三种正则表达式语法:

  1. 基本正则表达式(BRE):这是最基础的正则表达式形式,功能相对有限。在GNU版本的grep中,基本正则表达式和扩展正则表达式在功能上没有太大区别。

  2. 扩展正则表达式(ERE):扩展正则表达式提供了比基本正则表达式更强大的功能和更灵活的语法。例如,ERE允许使用圆括号进行分组和捕获,以及使用"|"(管道)符号表示"或"操作。

  3. Perl正则表达式(PCRE):Perl正则表达式是功能最强大、最灵活的正则表达式形式,提供了许多额外的功能和高级特性。这些特性可能不适用于所有系统,具体请参考pcresyntax手册文档。

在实践中,选择哪种正则表达式语法取决于你的需求和所使用的工具。对于简单的匹配任务,基本正则表达式可能就足够了。而对于更复杂和灵活的匹配需求,扩展正则表达式和Perl正则表达式提供了更多的选项和能力。

需要注意的是,不同的系统和工具可能对正则表达式的支持程度不同,因此在编写跨平台的脚本或程序时,应考虑到这些差异

3.1 基本结构

正则表达式是由匹配字符的模式构成的,可以用于匹配文本中的各种字符和字符串。以下是一些正则表达式元字符和结构:

  • 字符匹配:大多数字符在正则表达式中直接匹配自身,包括字母、数字和其他符号。

  • 特殊字符转义:如果想要匹配具有特殊含义的元字符(如.?*等),需要在其前面放置一个反斜杠\进行转义。

  • 基本正则表达式(BRE)元字符包括:
    .:匹配任意单个字符,除了换行符。
    *:匹配前面的字符0次或多次。
    [...]:字符类,匹配其中的任何一个字符。
    [^...]:否定字符类,匹配不在其中的任何一个字符。
    \:转义字符,用于去除后面字符的特殊含义或者匹配一些特殊字符。

  • 扩展正则表达式(ERE)元字符在BRE的基础上增加了一些,包括:
    ?:匹配前面的字符0次或1次。
    +:匹配前面的字符1次或多次。
    {m,n}:匹配前面的字符至少m次,至多n次。
    |:alternation,匹配左边或右边的表达式。
    ( ):分组,将多个字符视为一个整体进行匹配,并可以用于反向引用。
    \n:反向引用,引用之前定义的第n个子表达式匹配的内容。
    ^:在字符串开始处匹配。
    $:在字符串结束处匹配。

  • 正则表达式的组合:多个正则表达式可以连接在一起,结果是匹配各自正则表达式的并集。使用|操作符可以在两个正则表达式之间表示"或"操作。

  • 优先级和分组:重复操作(如*+?{})的优先级高于串接操作。反向引用又优先于交替操作。为了覆盖这些复杂的优先级规则,可以使用括号将一整个模式括起来,形成子模式。子模式可以通过反向引用号\n(n为子模式的编号)来引用。

说明:

  • 重复操作(如*、+、?、{})的优先级高于串接操作:这意味着在解析正则表达式时,重复操作会先于串接操作进行计算。例如,在表达式ab+c中,由于 * 的优先级高于 +,所以它会被解析为(ab)+c,即匹配任意数量的"a"后面跟着一个"c"。
  • 反向引用又优先于交替操作:反向引用是指在正则表达式中使用\n(n为子模式的编号)来引用之前已经定义过的子模式。当存在反向引用和交替操作(如 | )时,反向引用的优先级更高。例如,在表达式(a)b\1|c中,\1是一个反向引用,它优先于|运算符,所以这个表达式被解析为((a)b\1)|c,即匹配要么是"abab",要么是"c"。
  • 为了覆盖这些复杂的优先级规则,可以使用括号将一整个模式括起来,形成子模式:通过在需要改变优先级的表达式周围添加括号,可以强制改变运算的顺序。例如,在表达式a+bc中,如果不希望优先于+,可以写成(a+b)*c,这样就变成了先匹配一个或多个"a"+“b”,然后跟一个"c"。
  • 子模式可以通过反向引用号\n(n为子模式的编号)来引用:在正则表达式中,每个用括号括起来的子模式都会被分配一个编号,从左到右,第一个子模式的编号为1,第二个为2,以此类推。这些编号可以用在后面的表达式中,通过\n来进行引用。例如,在表达式(a(b)c)\2中,\2引用的是第二个子模式,即"b",所以这个表达式匹配的是"abc",其中"b"被重复了一次。

基本正则表达式(BRE)和扩展正则表达式(ERE)的主要区别有哪些?

  • 元字符的不同:
    • 基本正则表达式通常不支持+(匹配前面的字符1次或多次)、?(匹配前面的字符0次或1次)和{m,n}(匹配前面的字符至少m次,至多n次)这些量词。
    • 扩展正则表达式支持上述的+?{m,n}量词。
       
  • alternation(分支选择)的不同:
    • 基本正则表达式使用\|进行分支选择,例如a\|b匹配"a"或"b"。
    • 扩展正则表达式使用|进行分支选择,例如a|b匹配"a"或"b"。
       
  • 分组和捕获的不同:
    • 基本正则表达式使用\(\)进行分组,但不支持捕获和反向引用。
    • 扩展正则表达式也使用()进行分组,并且支持捕获和反向引用。可以通过\n引用之前定义的第n个子表达式的匹配内容。
       
  • 字符类的不同:
    • 基本正则表达式和扩展正则表达式都支持 [...][^...] 字符类,但在某些实现中,扩展正则表达式可能支持更多的预定义字符类或者自定义字符类范围。
       
  • 开始和结束锚定的不同:
    • 在某些实现中,基本正则表达式可能需要使用 \ 进行转义,如 ^\ 表示字符串开始,$\ 表示字符串结束。
    • 扩展正则表达式通常可以直接使用 ^ 表示字符串开始,$ 表示字符串结束。
       
  • 转义字符的不同:
    • 基本正则表达式中的某些元字符(如.*?等)在使用时通常需要进行转义。
    • 扩展正则表达式中的一些元字符可能不需要转义,但具体情况取决于具体实现。

3.2 字符集和括号表达式(不常用)

在正则表达式中,可以使用特定的字符类来匹配特定类型的字符。以下是一些常见的字符类及其含义:

  • 为获得传统shell通配符(如*?)的行为,需要将环境变量LC_ALL设置为C

  • [...]括号表示一个字符列表,其中可以包含单个字符或范围。例如:
    [:alnum:]:匹配任意字母数字字符(等同于[0-9A-Za-z])。
    [:alpha:]:匹配任意字母字符(等同于[A-Za-z])。
    [:blank:]:匹配空格和制表符。
    [:cntrl:]:匹配控制字符(ASCII值000到037和177(del))。
    [:digit:]:匹配0到9的数字。
    [:graph:]:匹配可打印字符,包括字母数字和标点符号(等同于[!-~])。
    [:lower:]:匹配小写字母。
    [:print:]:匹配可打印字符,包括字母数字、标点符号和空格。
    [:punct:]:匹配标点符号(! " # $ % & ’ ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ‘ { | } ~)。
    [:space:]:匹配空白字符,包括空格、制表符、换页符等。
    [:upper:]:匹配大写字母。
    [:xdigit:]:匹配十六进制数字(0-9、A-F、a-f)。

  • 在字符列表中,特殊字符需要进行转义,例如要匹配字符],应写为\]。如果要在列表中使用-作为字符,应将其放在第一位或最后一位,否则它会被解释为范围符号。

  • 正则表达式中的其他特殊字符和符号:
    .:匹配任意单个字符(除换行符外)。
    ^:在字符列表中,表示字符不在列表中;在字符串开始处,表示匹配行的开始。
    $:在字符串结束处,表示匹配行的结束。

  • 类别元字符:(不常用)
    [::开启类别字符。
    :]:关闭类别字符。

  • 排序符号:(不常用)
    [.:打开排序符号。
    .]:关闭排序符号。

  • 等价类:(不常用)
    [=:打开等价类。
    =]:关闭等价类。

通过熟练使用这些字符类和特殊符号,可以更精确地构造正则表达式来匹配各种文本模式。需要注意的是,不同的编程语言和工具可能对正则表达式的语法支持程度略有不同。

3.3 反斜杠字符和特殊表达式(不常用)

在正则表达式中,反斜线\字符通常用于转义特殊字符或表示特定的特殊表达式。以下是一些常见的反斜线字符和特殊表达式:

  • \b:匹配一个单词边界,即位于单词与空格、标点符号或其他非单词字符之间的位置。

  • \B:匹配一个非单词边界,即不位于单词与空格、标点符号或其他非单词字符之间的位置。

  • \<\>:在某些正则表达式实现中(如Perl和PCRE),这两个表达式分别匹配单词的开始和结束位置。

  • \w:匹配任何字母数字字符或下划线,等同于[a-zA-Z0-9_]

  • \W:匹配任何非字母数字字符和非下划线,等同于[^a-zA-Z0-9_]

  • \s:匹配任何空白字符,包括空格、制表符、换页符等。

  • \S:匹配任何非空白字符。

这些特殊表达式在构建复杂的正则表达式时非常有用,可以更精确地定位和匹配文本中的模式。需要注意的是,不同的编程语言和工具可能对正则表达式的语法支持程度略有不同。

3.4 锚位:

  • ^:用于匹配字符串的起始位置。例如,正则表达式^abc会匹配以"abc"开头的字符串。
  • $:用于匹配字符串的结束位置。例如,正则表达式xyz$会匹配以"xyz"结尾的字符串。

3.5 反向引用和子表达式:

  • 反向引用\n(n为一个数字)允许你引用之前定义的第n个子表达式匹配的内容。例如,正则表达式(a)\1会匹配连续的两个"a"字符。
  • 如果反向引用未匹配到任何内容,那么整个匹配可能会失败。例如,在表达式a(.)|b\1中,如果尝试匹配"ba",由于\1未能匹配到任何内容,所以整个匹配失败。
  • 处理多个表达式和子表达式:
     
    使用-e选项可以指定多个正则表达式。例如,grep -e 'abc' -e 'def' file.txt会搜索包含"abc"或"def"的行。
     
    使用-f file选项可以从文件中读取多个正则表达式。文件中的每一行都被视为一个独立的正则表达式。

3.6 基本正则与扩展正则使用原则

基本正则表达式和扩展正则表达式在语法和元字符的使用上存在一些区别(3.1 基本结构 也做了补充):

  1. 在基本正则表达式(BRE)中,某些元字符如?, +, {, |, (, and )失去了它们的原来含义,通常需要加上反斜线\?, \+, \{, \|, \(, and \)来进行转义,以便它们能够被解释为元字符。

  2. 传统的egrep(等价于grep -E)在某些实现中可能不支持直接使用{}作为量词。因此,为了可移植性,建议在grep -E模式中避免使用{}。可以使用 [{}] 来匹配字面意义上的大括号 {}

为了确保脚本在不同系统和版本的grep工具上都能正确运行,建议在编写脚本时遵循以下原则:

  • 如果只需要基本的正则表达式功能,使用基本正则表达式语法,并适当转义元字符。
  • 如果需要使用扩展正则表达式的功能,使用grep -Eegrep命令,并注意元字符的使用和可移植性问题。
  • 对于可能引起兼容性问题的特殊字符或构造,如{},尽量使用可移植的替代方案,如 [{}]

通过遵循这些原则,可以提高脚本的兼容性和可靠性,使其在不同的环境中都能正常工作。

4. 用法总结

以下是一些基本和常用的grep命令示例,这些示例应该能够覆盖大部分常见的grep应用场景。

  1. 搜索包含特定字符串的文件:grep "string" file.txt
  2. 在多个文件中搜索字符串:grep "string" file1.txt file2.txt file3.txt
  3. 使用反向引用搜索:grep -e 'regex1' -e 'regex2' files*
  4. 忽略大小写搜索:grep -i "string" file.txt
  5. 只显示匹配行的行号:grep -n "string" file.txt
  6. 只显示文件名:grep -l "string" file.txt
  7. 只显示不包含匹配行的文件名:grep -L "string" file.txt
  8. 显示匹配行的上下文(前两行和后两行):grep -C 2 "string" file.txt
  9. 使用固定字符串搜索:grep -F "string" file.txt
  10. 使用Perl兼容正则表达式:grep -P "regex" file.txt
  11. 递归搜索目录:grep -r "string" /path/to/directory
  12. 只在文本文件中搜索:grep -I "string" /path/to/directory
  13. 排除特定文件或目录:grep -r --exclude='*.log' "string" /path/to/directory
  14. 使用文件包含匹配模式:grep -f pattern_file.txt input_files*
  15. 搜索以特定字符开始的行:grep '^string' file.txt
  16. 搜索以特定字符结束的行:grep 'string$' file.txt
  17. 使用OR操作符搜索:grep -E 'string1|string2' file.txt
  18. 匹配单词边界:grep '\bstring\b' file.txt
  19. 匹配空行:grep '^$' file.txt
  20. 匹配空白行:grep '^[[:space:]]*$' file.txt
  21. 匹配数字:grep '[0-9]' file.txt
  22. 匹配字母:grep '[a-zA-Z]' file.txt
  23. 匹配换行符:grep $'\n' file.txt
  24. 匹配制表符:grep $'\t' file.txt
  25. 匹配多个连续的相同字符:grep 'string++' file.txt
  26. 匹配一个或多个字符:grep 's+t+ring' file.txt
  27. 匹配零个或多个字符:grep 's*t*ring' file.txt
  28. 匹配前面的字符出现一次或多次:grep 'str+ing' file.txt
  29. 匹配前面的字符出现零次或一次:grep 'str?ing' file.txt
  30. 使用括号进行分组和捕获:grep '(s)t(r)ing' file.txt
  31. 使用量词匹配特定次数的字符:grep 'str{3}ing' file.txt
  32. 使用量词匹配范围内的字符次数:grep 'str{2,4}ing' file.txt
  33. 使用括号指定选项:grep --color=auto "string" file.txt
  34. 在标准输入中搜索:echo "text" | grep "string"
  35. 在多个文件中搜索并输出文件名和匹配行:grep -H "string" file1.txt file2.txt
  36. 查找不含某个字符串的行:grep -v "string" file.txt
  37. 使用扩展正则表达式:grep -E "regex" file.txt
  38. 查找只包含某个字符串的行:grep -x "string" file.txt
  39. 使用八进制转义字符:grep $'\041' file.txt (匹配感叹号)
  40. 使用十六进制转义字符:grep $'\x21' file.txt (匹配感叹号)
  41. 查找以某个字符串开头的文件:find . -type f -exec grep -q "string" {} \; -print
  42. 查找以某个字符串结尾的文件:find . -type f -exec grep -q "string$" {} \; -print
  43. 使用颜色高亮匹配:grep --color "string" file.txt
  44. 在多个文件中搜索并统计每个文件中的匹配次数:grep -c "string" file1.txt file2.txt
  45. 在多个文件中搜索并统计所有文件中的总匹配次数:grep -rc "string" file1.txt file2.txt
  46. 使用固定的行数上下文:grep -C 3 "string" file.txt
  47. 使用可变的行数上下文:grep -C $(expr $(wc -l < file.txt) / 2) "string" file.txt
  48. 使用地址范围进行搜索:sed -n '/start/,/end/p' file.txt | grep "string"
  49. 查找包含两个连续单词的行:grep -E 'word1.*word2' file.txt
  50. 查找不包含两个连续单词的行:grep -Ev 'word1.*word2' file.txt

至此,所有的 grep 命令已经介绍完。

你可能感兴趣的:(Linux,linux)