【Linux】命令 - grep

Posted by 西维蜀黍 on 2019-09-16, Last Modified on 2022-12-10

grep

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来。grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户。

Usage

$ grep
usage: grep [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
	[-e pattern] [-f file] [--binary-files=value] [--color=when]
	[--context[=num]] [--directories=action] [--label] [--line-buffered]
	[--null] [pattern] [file ...]

主要参数:

  • -c:只输出匹配行的计数。
  • -I:不区分大小写(只适用于单字符)。
  • -h:查询多文件时不显示文件名。
  • -l:查询多文件时,只输出包含了匹配字符传的文件的文件名。
  • -n:显示匹配行及行号。
  • -s:不显示不存在或无匹配文本的错误信息。
  • -v:显示不包含匹配文本的所有行。

查找文件

在多个文件中查询特定字符串

$ grep ‘test’ aa bb cc

输出在aa,bb,cc文件中匹配到 test 字符串的行。

在文件夹中查找存在特定字符串的文件

比如,我们在当前子目录下,查找哪些文件中存在字符串"aa":

$ grep aa ./*
grep: ./assets: Is a directory
./【刷题】LinkedList-Leetcode-138-Copy-List-with-Random-Pointer.md:![动画描述](assets/16a2de34a98aa550.gif)
./【刷题】LinkedList-Leetcode-160-Intersection-of-Two-Linked-Lists.md:aa
./【刷题】LinkedList-Leetcode-160-Intersection-of-Two-Linked-Lists.md:aa

默认情况下,grep 只搜索当前目录。如果此目录下有许多子目录,grep 会以如下形式列出:

$ grep: ./assets: Is a directory

这可能会使 ‘grep 的输出难于阅读。这里有两种解决的办法:

  • 搜索子目录:grep -r
  • 或忽略子目录:grep -d skip

查找所有以d字符开头作为文件名的文件,且文件中包含 test 字符串

$ grep ‘test’ d*

-l - 只列出包含匹配字符串的文件的文件名

$ grep -l "assets/*.*" ./*
./2

-r - 搜索子目录

$ grep -r 'string' /etc

默认情况下,grep 只搜索当前目录。如果此目录下有许多子目录,grep 会以如下形式列出:

$ grep: ./assets: Is a directory

-h - 查询多文件时不显示文件名

$ grep -h "assets/*.*" ./*
test1 ![img](assets/160_statement.png) test2

--include="s3*" - 只考虑特定文件名的文件

$ grep <keyword> --include=<file name pattern>

# 包含 abc 且文件名以 s3 开头的所有匹配内容
$ grep abc -rl --include="s3*" ./
.//s3_deploy.sh

-a - 视为文本文件

  • -a, --text: Process a binary file as if it were text; this is equivalent to the –binary-files=text option.
$ grep -a <keyword> 1.bin

当出现下面这种错误的时候,就可以加上 -a

$ grep -a "ormstats" 1.log
Binary file 1.log matches

匹配定制

-i - 不区分大小写地搜索

不区分大小写地搜索。默认情况区分大小写,

$ grep -i pattern files

-w - 只匹配整个单词

只匹配整个单词(单词意味着这个字符串的两侧有分隔符),而不是字符串的一部分(如输入 magic,匹配 magic,而 magical 不能被匹配),

$ grep -w pattern files

-F - 将输入模式视为一个普通字符串

$ cat aa.txt
/sw/

asdasd

sdsd
$ grep -F "/sw/" *.txt
/sw/

# or use --fixed-strings to search for an exact string (disables regular expressions):
$ grep --fixed-strings "exact_string" path/to/file

# escape character
$ grep -F "applicable/":true"

或匹配

输出匹配 pattern1 或 pattern2 的行:

$ grep pattern1 | pattern2 files

也可以,输出包含 ed 或者 at 字符的行的内容

$ cat test.txt | grep -E "ed|at"

与匹配

显示既匹配 pattern1 又匹配 pattern2 的行内容。

$ grep pattern1 files | grep pattern2

比如

$ grep proctm log/data.log | grep ormstats

输出 log/data.log 文件中既包含 proctm 又包含 ormstats 的行。

-v - 非匹配(匹配不包含特定字符串的所有行)

$ grep -v pattern1 files

比如我想查看apaceh日志中,非图片的浏览记录。可以使用以下命令:

$ tail -f /usr/loca/apache/logs/access.log | grep -v '.jpg'

这条命令就可以针对apaceh的用户访问记录中,除了.jpg 图片之外的浏览日志,这样可以针对我们更好的分析日志了。

当然你可以再加 |grep -v '.png' 这样又可以排除 .png 格式的图片访问日志。

控制输出

-o - 只输出匹配到的那个字符串部分

如果不包含 -o(不包含 -o 为默认情况),则会把匹配到的那个部分所在的那一整行都输出到 terminal。

$ cat ./file
test1 ![img](assets/160_statement.png) file
test3

$ grep "assets/*.*" ./file
test1 ![img](assets/160_statement.png) file

$ grep -o "assets/*.*" ./file
assets/160_statement.png)

而如果包含 -o 之后,只输出被匹配到的那部分字符串。

-n - 同时列出匹配字符串所在行的行号

$ grep -n "assets/*.*" ./file
1:test1 ![img](assets/160_statement.png) test2

这里列出了行号为 1。

-c - 输出匹配上模式的行的数量

比如,查找指定进程个数

$ ps -ef | grep -c svn

-m 1 - 只输出匹配上的第一个行(第二个行和后面的行都不输出,即使匹配上了)

grep与正则表达式

pattern正则表达式主要参数:

  • \: 忽略正则表达式中特殊字符的原有含义。
  • ^:匹配正则表达式的开始行。
  • $: 匹配正则表达式的结束行。
  • \<:从匹配正则表达式的行开始。
  • \>:到匹配正则表达式的行结束。
  • [<candidate_character>]:指定单个字符集合,如[A]表示只匹配字符 A
  • [<candidate_character>-<candidate_character>]:指定字符字符集合范围,如 [A-Z],即匹配A、B、C…或 Z 。
  • .:匹配任意的单个字符。
  • *:匹配任何长度从0到无穷的字符串。

Case 1 - 输出存在字符集合中任何一个字符的行的内容

输出包含任何小写字母的行

$ cat size.txt | grep '[a-b]' 
b124230
b034325
a081016
a022021
a061048
b103303
a013386
b044525

Case 2 - 不是特定字符开头

# 输出行首既不是以4,也不是以8开头的所有行的内容
$ grep '^[^48]' data.doc      

# 输出行首不是以 u 开头的所有行的内容
cat test.txt |grep ^[^u]

Case 3 - 输出以特定字符串结尾的行

$ cat test.txt | grep hat$

Misc

Use grep in Shell Script

targets=($(grep -HRl "pattern" .))
  • use of (...) for array creation in BASH.
  • use grep -l to get only file names in grep’s output

注意到,有一个问题是:

# 当前目录下,有三个文件
$ find .
.
./.DS_Store
./1.png
./1 2.png

$ my_files=(`find . | grep "png" | awk -F "\n" '{print $1}'`)
# or
$ my_files=($(find . | grep "png" | awk -F "\n" '{print $1}'))

$ echo $my_files
./1.png ./1 2.png
# get array's len
$ echo ${#my_files[@]}
3

即,如果文件的名称中包括空格时,获得的array会有问题。

grep with find

Grep can be used with any other command you like. Let’s say I want to find any log files containing the word spice. I can use the find command and pipe the results to grep as follows:

$ find . -name "\*.log" | grep -i spice

Here’s an example of the results:

./spice-vdagent.log

Reference