Linux Shell 脚本编程(6)—文本过滤(grep命令)

Linux Shell 脚本编程(6)—文本过滤(grep命令)

文本过滤

grep命令


  • 概念:grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。
  • 按照行方式处理文本。。。。

  • grep 命令格式:

    • grep [参数] 正则表达式 [文件]
  • 选项

    -a 不要忽略二进制数据。 
    -A<显示列数> 除了显示符合范本样式的那一行之外,并显示该行之后的内容。 
    -b 在显示符合范本样式的那一行之外,并显示该行之前的内容。 
    -c #计算符合范本样式的列数。 (只输出匹配行的计数)
    -C<显示列数>或-<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。  
    -d<进行动作> 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep命令将回报信息并停止动作。 
    -e<范本样式> #指定字符串作为查找文件内容的范本样式。 
    
    -E #将范本样式为延伸的普通表示法来使用,意味着使用能使用扩展正则表达式。
    
    -f<范本文件> 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一列的范本样式。 
    -F 将范本样式视为固定字符串的列表。 
    -G 将范本样式视为普通的表示法来使用。 
    -h #在显示符合范本样式的那一列之前,不标示该列所属的文件名称。 
    -H 在显示符合范本样式的那一列之前,标示该列的文件名称。 
    -i 胡列字符大小写的差别。 
    -l 列出文件内容符合指定的范本样式的文件名称。 
    -L 列出文件内容不符合指定的范本样式的文件名称。 
    -n #在显示符合范本样式的那一列之前,标示出该列的编号。 (显示匹配行及行号)
    -q 不显示任何信息。 
    -R/-r 此参数的效果和指定“
    -d recurse”参数相同。 
    -s #不显示错误信息。 
    -v #反转查找。 ---显示不包含匹配文本的所有行。
    -w 只显示全字符合的列。 
    -x 只显示全列符合的列。 
    -y 此参数效果跟“-i”相同。 
    -o #只输出文件中匹配到的部分。
  • grep执行步骤

    • (1) 把下一输入行复制到模式空间中. 模式空间是只可保存一个文本行的缓冲区.
    • (2) 对模式空间应用正则表达式.
    • (3) 如果有匹配存在,该行从模式空间中被复制到标准输出.

    • grep实用程序对输入的每行重复这三个操作步骤.

  • 注意特殊情形!!

    • 1 . grep是一个搜索程序,它只能搜索匹配一个正则表达式的一行的存在性.
    • 2 . grep可以对一行采取唯一的动作是把它发送到标准输出. 如果该行不匹配正则表达式,则其不被打印.
    • 3 . 行的选择只基于正则表达式. 行编号或其他准则不能用于选择行.
    • 4 . grep是一个过滤器. 它可用在管道的左边或右边.
    • 5 . grep不能用于增加,删除或修改行.
    • 6 . grep不能用于只打印行的一部分.
    • 7 . grep不能只读取文件的一部分.
    • 8 . grep不能基于前面的内容或下一行来选择一行.只有一个缓冲区,它只保存当前行.

1. 搜索包含特定模式的文本行:

grep pattern file
grep "pattern" file 
#在file文件中查找包含"pattern"的文本行

jianliu@ubuntu:~/aa$ cat test0.txt
pattern
pattern1
padf
pattern 1
pattfs  2

jianliu@ubuntu:~/aa$ grep pattern test0.txt
pattern
pattern1
pattern 1

jianliu@ubuntu:~/aa$ grep "pattern" test0.txt
pattern
pattern1
pattern 1

2. 从stdin中搜索包含特定模式的文本行:

jianliu@ubuntu:~$ echo -e "this is a word \nnext line" | grep word 
this is a word 

3. 从stdin中搜索包含特定模式的文本行:

grep "math_word" file1 file2 file3

grep "match_word" *.doc  #在所有.doc文件中查找

grep "match_word" *    #在所有目录及文件中查找

4. 用–color选项可以在输出行中着重标记出匹配到的单词

grep match_word file --color=auto

5. -E 使用正则表达式进行匹配:(不需要进行转义处理!!)

jianliu@ubuntu:~$ cat test0.txt
word1
aword2
word3
1word4
word@
wor3
wo3
word12

#以匹配串结尾
jianliu@ubuntu:~$ grep -E '[a-z]{3,4}[0-9]$' test0.txt
word1
aword2
word3
1word4
wor3

#!!!!!注意!!!!----------------------
#   注意两种写法的区别
//     (1) grep -E  pattern 则后面的正则表达式不需要转义处理!!
//    (2grep pattern   后面的正则表达式需要进行转义处理!!
jianliu@ubuntu:~$ more  test0.txt | grep '[a-z]\{3,4\}[0-9]$'
word1
aword2
word3
1word4
wor3


#只要包含匹配串
jianliu@ubuntu:~$ grep -E '[a-z]{3,4}[0-9]' test0.txt
word1
aword2
word3
1word4
wor3
word12

#以匹配串开头
jianliu@ubuntu:~$ grep -E '^[a-z]{3,4}[0-9]' test0.txt
word1
word3
wor3
word12

##---注意事项!!!

  • #!!!!!注意!!!!———————-
  • # 注意两种写法的区别
  • (1) grep -E pattern 则后面的正则表达式不需要转义处理!!
  • (2) grep pattern 后面的正则表达式需要进行转义处理!!

  • 正则表达式的grep命令——egrep
jianliu@ubuntu:~$ egrep '[a-z]{3,4}[0-9]$' test0.txt
word1
aword2
word3
1word4
wor3

6. -o, 只输出文件中匹配到的文本部分:

jianliu@ubuntu:~$ echo this is a line | grep -o line
line

7. -v 刷选出除掉包含match_pattern行之外的所有行:

$ grep -v match_pattern file
选项-v可以将匹配结果进行反转(invert)。

jianliu@ubuntu:~$ cat test0.txt
word1
aword2
word3
1word4
word@
wor3
wo3
word12
abcde
wore21
12345

jianliu@ubuntu:~$ grep -v 'word' test0.txt
wor3
wo3
abcde
wore21
12345

8. -c 统计文件或文本中包含匹配字符串的行数

jianliu@ubuntu:~$ grep -c 'word' test0.txt
6


//需要注意的是-c只是统计匹配行的数量,并不是匹配的次数。例如:
jianliu@ubuntu:~$ echo -e "1 2 3 4\nhello\n5 6 7" | grep -c "[0-9]"
2
//尽管有6个匹配项,但命令只打印出2,这是因为只有两个匹配行。在单行中出现的多次匹配只被统计为一次。

9. 统计文件中匹配项的数量:

jianliu@ubuntu:~$ echo -e "1 2 3 4\nhello\n5 6 7" | grep -o "[0-9]" | wc -l
7

10. -n 打印包含匹配字符串的行号:

$ cat sample1.txt
gnu is not unix
linux is fun
bash is art
$ cat sample2.txt
planetlinux

$ grep linux -n sample1.txt
2:linux is fun

$ cat sample1.txt | grep -n linux
2:linux is fun
  • 涉及多个文件,随着输出结果打印对应文件名
$ grep linux -n sample1.txt sample2.txt
sample1.txt:2:linux is fun
sample2.txt:2:planetlinux

11. 打印样式匹配所位于的字符或字节偏移:

jianliu@ubuntu:~$ echo gnu is not unix | grep -b -o "not"
7:not

//一行中字符串的字符偏移是从该行的第一个字符开始计算,起始值是0。在上面的
//例子中, "not"的偏移值是7(也就是说, not是从该行的第7个字符开始的,即“ gnu is not unix”这一行)。
  • 选项 -b总是和 -o配合使用。

12. -l 搜索多个文件并找出匹配文本位于哪一个文件中:

$ grep -l linux sample1.txt sample2.txt
sample1.txt
sample2.txt
  • 和-l相反的选项是-L,它会返回一个不匹配的文件列表。

13. 递归地搜索文件

  • 如果需要在多级目录中对文本进行递归搜索,可以使用:
    • $ grep “pattern” [path] -R -n
    • 命令中的path指定了搜索目录。

jianliu@ubuntu:~$ grep "//jianliu" . -r -n
./aa/a1.c:5:    //jianliu
./hello.c:7:     //jianliu
 # . 表示当前目录,即/bin/home/jianliu
  • grep的选项-R和-r功能一样。

14. -i 忽略样式中的大小写

jianliu@ubuntu:~$ echo -e "hello\nword" | grep -i "HELLo"
hello

15. -e 匹配多个样式

  • 在进行匹配的时候通常只指定一个样式。然而,我们可以用选项 -e来指定多个匹配样式:
jianliu@ubuntu:~$ echo this is a line of text | grep -e "this" -e "line" -o
this
line
  • 可以提供一个样式文件用于读取样式。在样式文件中逐行写下需要匹配的样式,然后用选项 -f 执行grep:
jianliu@ubuntu:~$ cat pat_file
hello
cool

jianliu@ubuntu:~$ echo hello this is cool | grep -f pat_file
hello this is cool

16. 在grep搜索中指定或排除文件

  • grep可以在搜索过程中指定(include)或排除(exclude)某些文件。我们通过通配符来指
    定所include文件或exclude文件。

    • 目录中递归搜索所有的 .c和 .cpp文件:

      $ grep "main()" . -r --include *.c{c,cpp}
      
      #注意,some{str1,str2,str3}会扩展成somestr1,somestr2,somestr3。
      
    • 在搜索中排除所有的readme文件:

      $ grep "main()" . -r --exclude "readme"
    • 需要排除目录,可使用–exclude-dir选项。
    • 需要从文件中读取所需要排除的文件列表,使用–exclude-from FILE。

17. 使用0值字节作为后缀的grep与xargs

  • xargs命令通常用于将文件名列表作为命令行参数提供给其他命令。当文件名用作命令行参数时,建议用0值字节作为文件名终止符,而非空格。
  • 因为一些文件名中会包含空格字符,一旦它被误解为终结符,那么单个文件名就会被认为是两个文件名(例如, New file.txt被解析成New和file.txt两个文件名)。这个问题可以利用0值字节后缀来避免。
  • 我们使用xargs以便从诸如grep、find中接收stdin文本。这些命令可以将带有0值字节后缀的文本输出到stdout。为了指明输入的文件名是以0值字节(\0)作为终止符,需要在xargs中使用-0。
$ echo "test" > file1
$ echo "cool" > file2
$ echo "test" > file3
  • 在下面的命令序列中,grep使用-Z选项输出以0值字节作为终结符的文件名(\0)。
    xargs -0读取输入并用0值字节终结符分隔文件名:

    $ grep "test" file* -lZ | xargs -0 rm
    # -Z通常和-l结合使用

18. -q grep静默输出

  • 在静默模式中, grep命令不会输出任何内容。它仅是运行命令,然后根据命令执行成功与否返回退出状态。

  • 如果命令运行成功会返回0,如果失败则返回非0值。

//脚本: 利用grep的静默模式来测试文本匹配是否存在于某个文件中

jianliu@ubuntu:~/aa$ cat test0.sh
#!/bin/bash
#yong tu: ce shi wen jian shi fou bao han te ding de wen ben nei rong

if [ $# -ne 2 ]
then
    echo "usage: $0 match_text filename"
    exit 1
fi

match_text=$1
filename=$2
grep -q -E "$match_text" $filename

if [ $? -eq 0 ]
then
   echo -e "Yes\nthe text [$match_text] exists in the file [$filename]"
else
   echo -e "No\ntext [$match_text] does not exists in the file [$filename]"
fi
#---------------------------------------------------------------   

jianliu@ubuntu:~/aa$ ./test0.sh [a-z]{3}[0-9] student_data.txt
Yes
the text [[a-z]{3}[0-9]] exists in the file [student_data.txt]

jianliu@ubuntu:~/aa$ ./test0.sh bob1 student_data.txt
Yes
the text [bob1] exists in the file [student_data.txt]

19. 打印出匹配文本之前或之后的行

  • 需要匹配行之前或之后的n行,也可能两者皆要。这可以在grep中用前后行控制选项来实现。
# -A  要打印匹配某个结果之后的3行
 $ seq 10 | grep 5 -A 3
 5
 6
 7
 8


# -B  要打印匹配某个结果之前的3行
 $ seq 10 | grep 5 -B 3
 2
 3
 4
 5


# -C  要打印匹配某个结果之前以及之后的3行
 $ seq 10 | grep 5 -C 3
 2
 3
 4
 5
 6
 7
 8


# --  有多个匹配,使用--作为各部分之间的定界符
 $ echo -e "a\nb\na\nb\nc" | grep a -A 1
 a
 b
 --
 a
 b
  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值