目录
29. shell命令--grep
功能说明
grep、egrep 和 fgrep 是 Linux 和 Unix 系统上用于文本搜索的强大工具。这些命令允许用户搜索文件中的特定模式,并打印出匹配该模式的行。虽然 grep、egrep 和 fgrep 在功能上有所不同,但它们都是基于正则表达式的搜索工具。
grep 命令来自英文词组 global search regular expression and print out the line 的缩写,意思是用于全面搜索的正则表达式,并将结果输出。人们通常会将grep命令与正则表达式搭配使用,参数作为搜索过程中的补充或对输出结果的筛选,命令模式十分灵活。
与之容易混淆的是 egrep 命令和 fgrep 命令。如果把 grep 命令当作标准搜索命令,那么 egrep 则是扩展搜索命令,等价于 grep -E 命令,支持扩展的正则表达式。而fgrep则是快速搜索命令,等价于 grep -F 命令,不支持正则表达式,直接按照字符串内容进行匹配。
grep
grep 是 Global Regular Expression Print 的缩写,用于在文本文件中搜索指定的模式,并将包含该模式的行打印到标准输出。默认情况下,grep 使用基础正则表达式(BRE, Basic Regular Expression)。
不过,现代版本的 grep 通常支持 -E 选项来启用扩展正则表达式的功能,因此很多用户直接使用 grep -E 而不是 egrep。
egrep
egrep 是 Extended Global Regular Expression Print 的缩写,与 grep 类似,但默认使用扩展正则表达式(ERE, Extended Regular Expression)。扩展正则表达式提供了更多的功能和更灵活的匹配方式。
fgrep
fgrep 是 Fixed Global Regular Expression Print 的缩写,与 grep 类似,但它将模式视为固定字符串,而不是正则表达式。这意味着你可以搜索字面字符串,而无需担心正则表达式中的特殊字符。
但是,你也可以使用 grep -F 来达到相同的效果。
语法格式
SYNOPSIS
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
选项说明
-a --text # 不要忽略二进制数据。
-A <显示行数> --after-context=<显示行数> # 除了显示符合范本样式的那一行之外,并显示该行之后的内容。
-b --byte-offset # 在显示符合范本样式的那一行之外,并显示该行之前的内容。
-B<显示行数> --before-context=<显示行数> # 除了显示符合样式的那一行之外,并显示该行之前的内容。
-c --count # 计算符合范本样式的列数。
-C<显示行数> --context=<显示行数>或-<显示行数> # 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
-d<进行动作> --directories=<动作> # 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。
-e<范本样式> --regexp=<范本样式> # 指定字符串作为查找文件内容的范本样式。
-E --extended-regexp # 将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
-f<范本文件> --file=<规则文件> # 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。
-F --fixed-regexp # 将范本样式视为固定字符串的列表。
-G --basic-regexp # 将范本样式视为普通的表示法来使用。
-h --no-filename # 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
-H --with-filename # 在显示符合范本样式的那一列之前,标示该列的文件名称。
-i --ignore-case # 忽略字符大小写的差别。
-l --file-with-matches # 列出文件内容符合指定的范本样式的文件名称。
-L --files-without-match # 列出文件内容不符合指定的范本样式的文件名称。
-n --line-number # 在显示符合范本样式的那一列之前,标示出该列的编号。
-P --perl-regexp # PATTERN 是一个 Perl 正则表达式
-q --quiet或--silent # 不显示任何信息。
-R/-r --recursive # 此参数的效果和指定“-d recurse”参数相同。
-s --no-messages # 不显示错误信息。
-v --revert-match # 反转查找。
-V --version # 显示版本信息。
-w --word-regexp # 只显示全字符合的列(精准匹配这整词)。
-x --line-regexp # 只显示全列符合的列(精准匹配这整行)。
-y # 此参数效果跟“-i”相同。
-o # 只输出文件中匹配到的部分。
-m <num> --max-count=<num> # 找到num行结果后停止查找,用来限制匹配行数
正则表达式
^ # 锚定行的开始 如:'^grep'匹配所有以grep开头的行。
$ # 锚定行的结束 如:'grep$' 匹配所有以grep结尾的行。
. # 匹配一个非换行符的字符 如:'gr.p'匹配gr后接一个任意字符,然后是p。匹配任意单个字符,也可以是一个汉字
* # 匹配零个或多个先前字符 如:'*grep'匹配所有一个或多个空格后紧跟grep的行。
.* # 一起用代表任意字符。
[] # 匹配一个指定范围内的字符,如'[Gg]rep'匹配Grep和grep。
[^] # 匹配一个不在指定范围内的字符,如:'[^A-Z]rep' 匹配不包含 A-Z 中的字母开头,紧跟 rep 的行
\(..\) # 标记匹配字符,如'\(love\)',love被标记为1。
\< # 锚定单词的开始,如:'\<grep'匹配包含以grep开头的单词的行。
\> # 锚定单词的结束,如'grep\>'匹配包含以grep结尾的单词的行。
x\{m\} # 重复字符x,m次,如:'0\{5\}'匹配包含5个o的行。
x\{m,\} # 重复字符x,至少m次,如:'o\{5,\}'匹配至少有5个o的行。
x\{m,n\} # 重复字符x,至少m次,不多于n次,如:'o\{5,10\}'匹配5--10个o的行。
\w # 匹配文字和数字字符,也就是[A-Za-z0-9],如:'G\w*p'匹配以G后跟零个或多个文字或数字字符,然后是p。
\W # \w的反置形式,匹配一个或多个非单词字符,如点号句号等。
\b # 单词锁定符,如: '\bgrep\b'只匹配grep。
\S #匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\s #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即 A-Z, a-z
[:lower:] 小写字母,示例:[[:lower:]],相当于[a-z]
[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
实践操作
0. 环境准备
mkdir -p /test/grep
cd /test/grep
1. 搜索指定文件中包含某个关键词的内容行
grep "root" /etc/passwd
grep bin /etc/passwd
2. 搜索指定文件中以某个关键词开头的内容行
grep ^root /etc/passwd
grep ^mail /etc/passwd
3. 搜索指定文件中以某个关键词结尾的内容行
grep bash$ /etc/passwd
grep nologin$ /etc/passwd
4. 搜索多个文件中包含某个关键词的内容行
grep root /etc/passwd /etc/shadow
5. 搜索多个文件中包含某个关键词的内容,不显示文件名称
grep -h root /etc/passwd /etc/shadow
6. 显示指定文件中包含某个关键词的行数量
grep -c root /etc/passwd /etc/shadow
7. 搜索指定文件中包含某个关键词位置的行号及内容行
grep -n sbin /etc/passwd
8. 搜索指定文件中不包含某个关键词的内容行
grep nologin /etc/passwd
grep -v nologin /etc/passwd #取反
9. 搜索指定工作目录中包含某个关键词内容的文件,未找到则提示
grep root /etc/
grep root /etc/*
grep -l root /etc/*
grep root /etc/* |wc -l
grep -l root /etc/* |wc -l
10. 搜索指定工作目录中包含某个关键词内容的文件,未找到也不提示
grep -sl root /etc/*
11. 不仅搜索指定目录,还搜索其内子目录内是否有关键词文件
grep -srl root /etc/
grep -sl root /etc/* |wc -l
grep -srl root /etc/* |wc -l
12. 搜索指定文件中精准匹配到某个关键词的内容行
echo -e "cd\ncdrom\ncd rom"
echo -e "cd\ncdrom\ncd rom" |grep "cd"
echo -e "cd\ncdrom\ncd rom" |grep -w "cd" #精准匹配整个关键字
echo -e "cd\ncdrom\ncd rom" |grep -x "cd" #精准匹配关键字的行
13. 判断指定文件中是否包含某个关键词,通过返回状态值输出结果(0为包含,1为不包含),一般用于条件测试
grep -q root /etc/passwd
echo $?
grep -q rooot /etc/passwd
echo $?
14. 搜索指定文件中符合条件的行数
grep -c ^$ /etc/profile #空行总行数
grep -c ^$ /etc/passwd #空行总行数
grep root /etc/passwd
grep -c root /etc/passwd #包含root的总行数
grep root /etc/passwd |wc -l #这样也可以统计
15. 只输出文件中匹配到的部分
grep root /etc/passwd
grep -o root /etc/passwd
16. 打印样式匹配所位于的字符或字节偏移
#一行中字符串的字符偏移是从该行的第一个字符开始计算,起始值为0。
#选项 -b -o 一般总是配合使用
echo 123456789 |grep -o -b 5
echo 1234 56789 |grep -o -b 5
grep root /etc/passwd
grep -o -b root /etc/passwd
17. 忽略匹配样式中的字符大小写
echo "hello world" | grep "HEllo"
echo "hello world" | grep -i "HEllo"
18. 选项 -e 制动多个匹配样式
echo this is a test line
echo this is a test line | grep -e "is" -e "line"
echo this is a test line | grep -e "is" -e "line" -o
#也可以使用 -f 选项来匹配多个样式,在样式文件中逐行写出需要匹配的字符
echo -e "aaa\nbbb" >patfile
cat patfile
echo aaa bbb ccc ddd
echo aaa bbb ccc ddd |grep -f patfile
echo aaa bbb ccc ddd |grep -f patfile -o
19. 在grep搜索结果中包括或者排除指定文件
echo test >file.html
echo test >file.php
echo test >file.txt
head -v file*
#只在当前目录中所有的 .php 和 .txt 文件中递归搜索字符 test
grep test . -r --include=*.{php,txt}
#在搜索结果中排除所有 .bash_history 文件里的内容
grep test . -r
cp ~/.bash_history .
grep test . -r --exclude .bash_history
#在搜索结果中排除 filelist 文件列表里的文件
echo .bash_history >filelist
cat filelist
grep test . -r --exclude-from filelist
grep test . -r --exclude-from=filelist
20. 使用0值字节后缀的grep与xargs
echo aaa >file1
echo bbb >file2
echo aaa >file3
head -v file1 file2 file3
# grep 输出用 -Z 选项来指定以 0 值字节作为终结符文件名(\0),
# xargs -0 读取输入并用0值字节终结符分隔文件名,
#-Z 通常和 -l 结合使用
grep aaa file*
grep aaa file* -l
grep aaa file* -lZ
grep aaa file* -lZ |xargs -0
grep aaa file* -lZ |xargs -0 ls -l
grep aaa file* |xargs -0 ls -l
grep aaa file* -lZ |xargs -0 echo >> bbb
ls
cat bbb
21. 打印出匹配文本之前或者之后的行
seq 10
seq 10 |grep '5' -A 3 #显示匹配某个结果之后的N行
seq 10 |grep '5' -B 3 #显示匹配某个结果之前的N行
seq 10 |grep '5' -C 3 #显示匹配某个结果的前N行和后N行
echo -e "a\nb\nc\na\nb\nc"
echo -e "a\nb\nc\na\nb\nc" |grep 'a' -A 0 #如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符
echo -e "a\nb\nc\na\nb\nc" |grep 'a' -A 1
echo -e "a\nb\nc\na\nb\nc" |grep 'a' -A 2
注意事项
- egrep 和 fgrep 在很多系统上可能是 grep 的符号链接或别名,因此使用 grep -E 和 grep -F 可能是更可移植的方法。
- 正则表达式可以非常复杂,因此在使用这些工具时,了解正则表达式的语法和功能是非常重要的。
- 这些命令都支持大量的选项和参数,用于控制搜索的各个方面,如大小写敏感性、递归搜索等。你可以通过运行 man grep 来查看完整的文档和选项列表。