Linux Shell 脚本编程(6)—文本过滤(grep命令)
文本过滤
- 正则表达式 Linux Shell 脚本编程(5)—文本过滤(正则表达式)
- grep 命令 Linux Shell 脚本编程(6)—文本过滤(grep命令)
- find
- awk
- sed
- 合并与分割(sort、uniq、join、cut、paste、split)
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 则后面的正则表达式不需要转义处理!!
// (2)grep 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指定了搜索目录。
- $ grep “pattern” [path] -R -n
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