Linux shell文本三剑客之grep的使用

最近在看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

一、匹配控制

  1. -e pattern 模式(即匹配规则),多次使用-e或者和-f使用,会将每个匹配的整合一起,是并集

    # 打印包含1或2的行
    grep -e "1" -e "2" nums.txt
    
  2. -f file 模式都写在一个文件中,相当于-e的每个pattern写在文件中,以行分隔

    # 新建文件pattern
    cat>pattern<<-EOF
    1
    2
    EOF
    
    # 使用-f,与上面使用两个-e一样
    grep -f pattern nums.txt
    
  3. -i 不区分大小写

    # 匹配[a-c]的行,也可以匹配[A-C]
    grep -i "[a-c]" chars.txt
    
  4. -v 反转模式,匹配pattern没有匹配的行,可以用来排除

    # 匹配没有0-8的行
    grep -v [0-8] nums.txt
    
  5. -w 单词匹配,将pattern作为一个单词匹配

    仅选择包含构成整个单词的匹配项的行。测试结果表明, 匹配的子字符串必须位于行的开头, 或者前面有一个非单词的组成字符。同样, 它必须在行的末尾, 或者后面跟一个非单词的组成字符。单词组成字符是字母、数字和下划线。如果还指定了-x, 则此选项不起作用

    # 匹配单词hello,结果表明-hello-和hello匹配,单词组成是[0-9a-zA-Z_],其他可作为单词分隔
    grep -w "hello" words.txt
    
  6. -x 行匹配,仅选择与整行完全匹配的匹配项。类似于在正则中使用^行首和$行尾完全匹配的一行。

    # 可以匹配一行
    grep -x "hello world" words.txt
    # 不匹配
    grep -x "hello worl" words.txt
    

二、输出控制

  1. -c 为每个输入文件输出匹配到几行
    # 输出输入文件匹配行数
    grep -c '1' nums.txt words.txt chars.txt
    
  2. -L 打印没有匹配的输入文件的名字
    grep -L "hello" nums.txt words.txt chars.txt
    
  3. -l 打印匹配到的输入文件的名字
    grep -l "hello" nums.txt words.txt chars.txt
    
  4. -m num 每个输入文件最大匹配num次后,停止读入
    grep -m 2 "1" nums.txt words.txt chars.txt
    
  5. -o 打印匹配的部分,常用来打印正则匹配的结果
    # 打印匹配到的三个数字,正则中注意转义
    grep -o "[0-9]\{3\}" nums.txt words.txt chars.txt
    
  6. -q 静默模式,不会输出到标准输出
  7. -s 不输出文件不存在或不可读的错误信息。
    # aaaaa.txt不存在
    grep "1" nums.txt words.txt chars.txt aaaaa.txt
    grep -s "1" nums.txt words.txt chars.txt aaaaa.txt
    

三、输出行前缀控制

当输出多个前缀字段时, 顺序始终是文件名、行号和字节偏移量, 而不考虑指定这些选项的顺序

  1. -b 字节偏移量, 匹配的结果会在文件名后输出----相对文件开始(0字节)到匹配结果的字节偏移
    grep -b "12" nums.txt words.txt
    
  2. -H 打印文件名,当超过1个文件时,这个默认生效
    # 使用-H,可以当1个输入文件时显示文件名
    grep -bH "12" nums.txt
    
  3. -h 不打印文件名,当只有1个文件时,这是默认设置
    # 使用-h,可以当多个输入文件时不显示文件名
    grep -h "12" nums.txt words.txt
    
  4. –label=LABEL 将来自标准输入看做文件名为LABEL的文件
    # 将标准输入看做文件名为myInputFile的文件
    cat nums.txt | grep -H "12" --label=myInputFile
    
  5. -n 显示匹配的在输入文件的行号,作为输出的前缀
    grep -n "12" nums.txt words.txt
    
  6. -T 当输出一行包含文件名,行号或字符偏移时,会用\t分隔
    grep -T "12" nums.txt words.txt
    
  7. -u 当使用-b时,会输出unix风格字节偏移
  8. -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选项,则这些选项无效,并且在使用它们时给出警告

  1. -A num 匹配行后面num行,包含匹配行
    # 多文件中,文件名后跟:表示匹配行,-表示附近的行
    grep -A 2 "123" nums.txt chars.txt words.txt
    
  2. -B num 匹配行前面num行,包含匹配行
    grep -B 2 "123" nums.txt chars.txt words.txt
    
  3. -C num 或-num,匹配行前后num行,包含匹配行
    grep -C 2 "123" nums.txt chars.txt words.txt
    

五、文件目录选择

  1. -a 像文本文件一样处理二进制文件

  2. -D action 如果输入文件是设备、FIFO、Socket ,使用action来处理

    如果action为read, 那么所有设备像普通文件一样读取。
    如果action为skip,那么自动跳过设备、FIFO、Socket。
    默认情况下,如果命令行有设备,或者使用-R(递归,目录下有设备),那么读取设备,如果使用-r,则跳过设备。
    这个选项对通过标准输入读取的文件无效。

  3. -d action 如果输入文件是目录,使用action来处理。

    默认action为read, 会像普通文件一样读取,有些操作系统不允许,那么就会报错,或者跳过。在我的测试使用中,可能会卡住。
    如果action为skip,那么就会跳过目录。
    如果action为recurse,那么就递归读取目录下所有文件,相当于-r。

  4. -r 递归读取目录下文件

六、其他选项

  1. -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
    
  2. -P perl正则,一些正则的高级应用需要用到这个选项
    # 获取链接
    grep -oP '(?<=href=").*?(?=">)' data
    

更多细节可以查看官方文档:http://www.gnu.org/software/grep/manual/grep.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章