最近在看grep的官方文档,记录下这些自己练习的例子
准备
新建3个测试文件
# 生成1到100
seq 1 100 > nums.txt
cat>words.txt<<-EOF
hello world
Common methods to solve matrix related problem include DFS, BFS, dynamic programming, etc.
hello123 world123
-hello-
_hello_
EOF
# 生成ASCII表中A到z,包含A-Za-z
printf "%s\n" {A..z} > chars.txt
一、匹配控制
-
-e pattern 模式(即匹配规则),多次使用-e或者和-f使用,会将每个匹配的整合一起,是并集
# 打印包含1或2的行 grep -e "1" -e "2" nums.txt
-
-f file 模式都写在一个文件中,相当于-e的每个pattern写在文件中,以行分隔
# 新建文件pattern cat>pattern<<-EOF 1 2 EOF
# 使用-f,与上面使用两个-e一样 grep -f pattern nums.txt
-
-i 不区分大小写
# 匹配[a-c]的行,也可以匹配[A-C] grep -i "[a-c]" chars.txt
-
-v 反转模式,匹配pattern没有匹配的行,可以用来排除
# 匹配没有0-8的行 grep -v [0-8] nums.txt
-
-w 单词匹配,将pattern作为一个单词匹配
仅选择包含构成整个单词的匹配项的行。测试结果表明, 匹配的子字符串必须位于行的开头, 或者前面有一个非单词的组成字符。同样, 它必须在行的末尾, 或者后面跟一个非单词的组成字符。单词组成字符是字母、数字和下划线。如果还指定了-x, 则此选项不起作用
# 匹配单词hello,结果表明-hello-和hello匹配,单词组成是[0-9a-zA-Z_],其他可作为单词分隔 grep -w "hello" words.txt
-
-x 行匹配,仅选择与整行完全匹配的匹配项。类似于在正则中使用^行首和$行尾完全匹配的一行。
# 可以匹配一行 grep -x "hello world" words.txt # 不匹配 grep -x "hello worl" words.txt
二、输出控制
- -c 为每个输入文件输出匹配到几行
# 输出输入文件匹配行数 grep -c '1' nums.txt words.txt chars.txt
- -L 打印没有匹配的输入文件的名字
grep -L "hello" nums.txt words.txt chars.txt
- -l 打印匹配到的输入文件的名字
grep -l "hello" nums.txt words.txt chars.txt
- -m num 每个输入文件最大匹配num次后,停止读入
grep -m 2 "1" nums.txt words.txt chars.txt
- -o 打印匹配的部分,常用来打印正则匹配的结果
# 打印匹配到的三个数字,正则中注意转义 grep -o "[0-9]\{3\}" nums.txt words.txt chars.txt
- -q 静默模式,不会输出到标准输出
- -s 不输出文件不存在或不可读的错误信息。
# aaaaa.txt不存在 grep "1" nums.txt words.txt chars.txt aaaaa.txt grep -s "1" nums.txt words.txt chars.txt aaaaa.txt
三、输出行前缀控制
当输出多个前缀字段时, 顺序始终是文件名、行号和字节偏移量, 而不考虑指定这些选项的顺序
- -b 字节偏移量, 匹配的结果会在文件名后输出----相对文件开始(0字节)到匹配结果的字节偏移
grep -b "12" nums.txt words.txt
- -H 打印文件名,当超过1个文件时,这个默认生效
# 使用-H,可以当1个输入文件时显示文件名 grep -bH "12" nums.txt
- -h 不打印文件名,当只有1个文件时,这是默认设置
# 使用-h,可以当多个输入文件时不显示文件名 grep -h "12" nums.txt words.txt
- –label=LABEL 将来自标准输入看做文件名为LABEL的文件
# 将标准输入看做文件名为myInputFile的文件 cat nums.txt | grep -H "12" --label=myInputFile
- -n 显示匹配的在输入文件的行号,作为输出的前缀
grep -n "12" nums.txt words.txt
- -T 当输出一行包含文件名,行号或字符偏移时,会用\t分隔
grep -T "12" nums.txt words.txt
- -u 当使用-b时,会输出unix风格字节偏移
- -Z 和find -print0’, ‘perl -0’, ‘sort -z’, ‘xargs -0’类似,处理任意文件名,后跟一个NULL字符
# 新建一个文件名包含空格的测试文件 cat>"123 456.txt"<<-EOF hello 123 EOF
# xargs会以空格分隔文件名,当文件名有空格时,以下会报错 find . -name "*.txt" | xargs grep "hello" # find使用-print0文件名后为一个NULL,xargs使用-0也以NULL作为文件分隔,这样就不会有问题 find . -name "*.txt" -print0 | xargs -0 grep "hello"
# 假设文件名不包含空格时,以下没问题 grep -l "hello" nums.txt words.txt chars.txt | xargs cat # 当文件名包含空格时,就会出问题 grep -l "hello" nums.txt words.txt chars.txt "123 456.txt" | xargs cat # 打印包含hello的文件所有内容 grep -lZ "hello" nums.txt words.txt chars.txt "123 456.txt" | xargs -0 cat
四、上下文行控制
所谓的上下文行就是在匹配行附近的行,只有当使用下列选项之一时,才会输出它们。无论如何设置这些选项,grep都不会多次输出任何给定行,如果指定了-o选项,则这些选项无效,并且在使用它们时给出警告
- -A num 匹配行后面num行,包含匹配行
# 多文件中,文件名后跟:表示匹配行,-表示附近的行 grep -A 2 "123" nums.txt chars.txt words.txt
- -B num 匹配行前面num行,包含匹配行
grep -B 2 "123" nums.txt chars.txt words.txt
- -C num 或-num,匹配行前后num行,包含匹配行
grep -C 2 "123" nums.txt chars.txt words.txt
五、文件目录选择
-
-a 像文本文件一样处理二进制文件
-
-D action 如果输入文件是设备、FIFO、Socket ,使用action来处理
如果action为read, 那么所有设备像普通文件一样读取。
如果action为skip,那么自动跳过设备、FIFO、Socket。
默认情况下,如果命令行有设备,或者使用-R(递归,目录下有设备),那么读取设备,如果使用-r,则跳过设备。
这个选项对通过标准输入读取的文件无效。 -
-d action 如果输入文件是目录,使用action来处理。
默认action为read, 会像普通文件一样读取,有些操作系统不允许,那么就会报错,或者跳过。在我的测试使用中,可能会卡住。
如果action为skip,那么就会跳过目录。
如果action为recurse,那么就递归读取目录下所有文件,相当于-r。 -
-r 递归读取目录下文件
六、其他选项
- -E 使用拓展正则表达式
cat>data<<-EOF <a href="http://www.baidu.com">百度一下</a>" hello hellohello able ableable 12321 abcba EOF
# 使用()可以使用组 # 匹配5个字符,回文字符,类似 12321 grep -oE '(.)(.).\2\1' data # 匹配 hellohello grep -oE '([a-z]{5})\1' data
- -P perl正则,一些正则的高级应用需要用到这个选项
# 获取链接 grep -oP '(?<=href=").*?(?=">)' data
更多细节可以查看官方文档:http://www.gnu.org/software/grep/manual/grep.html