shell的grep命令

Shell 的 grep 命令详解(新手详细版)

本文档面向零基础新手,从“grep 是干什么的”讲起,详细说明基本用法、常用选项、正则表达式、多文件与递归、实用示例等,并配有大量示例。


一、grep 是什么?

1.1 一句话理解

grep 用来在文本按“模式”(字符串或正则)查找,把包含该模式的那一行整行打印出来。

  • globally search for a regular expression and print(在全文里按正则搜索并打印)。
  • 输入可以来自:文件管道传过来的前一个命令的输出。
  • 不修改文件,只做“查找并显示”。

1.2 典型用途

  • 在日志里找报错、关键字;
  • 在代码里找函数名、配置项;
  • 在命令输出里筛出需要的行(配合管道 |)。

二、基本语法

grep [选项] 模式 [文件...]
  • 模式:要搜的字符串或正则表达式(见后文)。
  • 文件:一个或多个文件;不写则从标准输入读(常和管道一起用)。

示例:

# 在 file.txt 里找包含 "hello" 的行
grep "hello" file.txt

# 在多个文件里找
grep "error" log1.txt log2.txt

# 前一个命令的输出里找(标准输入)
cat file.txt | grep "hello"
ls -l | grep ".txt"

三、最常用选项(先记这些)

选项 含义 示例
-i 忽略大小写 grep -i "error" log.txt
-n 显示行号 grep -n "hello" file.txt
-v 反向:只显示不包含模式的行 grep -v "^#" config.conf
-c 只显示匹配行数,不显示内容 grep -c "error" log.txt
-l 只显示有匹配的文件名,不显示具体行 grep -l "TODO" *.c
-L 只显示没有匹配的文件名 grep -L "TODO" *.c
-r-R 递归在目录下所有文件中搜 grep -r "function" ./src
-w 整词匹配(前后是“非单词字符”或边界) grep -w "root" file.txt
-x 整行匹配(整行就是模式) grep -x "admin" users.txt
-q 安静模式:只根据是否匹配设置退出码,不输出 脚本里用 if grep -q "ok" file; then ...

可以组合:grep -in "error" log.txt(忽略大小写 + 显示行号)。


四、按“行前后”显示:-A、-B、-C

有时不仅想看匹配的那一行,还想看前后几行(如日志的上下文)。

选项 含义
-A n 匹配行后面 n 行也显示(After)
-B n 匹配行前面 n 行也显示(Before)
-C n 匹配行前后各 n 行(Context)

示例:

# 匹配行及后面 2 行
grep -A 2 "error" log.txt

# 匹配行及前面 2 行
grep -B 2 "error" log.txt

# 匹配行前后各 3 行
grep -C 3 "Exception" app.log

输出里会用 -- 分隔不同匹配块。


五、正则表达式(模式里能写什么)

grep 的模式默认是“基本正则”(BRE);加 -E 是“扩展正则”(ERE),写法更直观。下面先按“常用写法”讲,需要时说明 BRE/ERE 区别。

5.1 普通字符

大部分字符就是字面意思hello 就匹配字母 h、e、l、l、o 连在一起。

grep "hello" file.txt

5.2 特殊字符与转义

以下字符在正则有特殊含义,要匹配字面时需转义(前面加 ):

字符 含义(正则) 匹配字面写法
. 任意一个字符 .
* 前一个字符出现 0 次或多次 *
^ 行首 ^
$ 行尾 $
[ ] 字符集合 []
转义符 \

示例:

# 匹配 "file." 后面跟任意一个字符(如 file.txt、file1)
grep "file." file.txt

# 匹配以 "error" 开头的行
grep "^error" log.txt

# 匹配以 "end" 结尾的行
grep "end$" file.txt

# 匹配空行(行首紧跟行尾)
grep "^$" file.txt

5.3 点 . 和星号 *

  • .:匹配任意一个字符(除换行)。
  • *``(基本正则):前一个字符出现 0 次或多次**。
# 匹配 f 后跟任意两个字符,如 fit、fat、f12
grep "f.." file.txt

# 匹配 若干数字(0~9 出现 0 次或多次,要配合 [0-9])
# 基本正则里:grep "[0-9]*" 可能不是你想的“一整串数字”,见下节

5.4 字符类 [ ]

  • [abc]:匹配 a、b、c 中任意一个
  • [0-9]:一个数字;[a-z]:一个小写字母;[A-Z]:一个大写字母。
  • [^abc] a、b、c 外的任意一个字符(^ 在 [ ] 内表示“取反”)。
# 匹配包含数字的行
grep "[0-9]" file.txt

# 匹配以数字开头的行
grep "^[0-9]" file.txt

# 匹配非空行(行首不是换行,即至少有一个非空字符)
grep "." file.txt
# 或排除空行:
grep -v "^$" file.txt

5.5 扩展正则 -E:+、?、|、()

-E 后可用扩展正则,更易写:

写法 含义
+ 前一个字符 1 次或多次
? 前一个字符 0 次或 1 次
| 或,如 a|b 表示 a 或 b
() 分组,如 (err|ERR)

示例:

# 匹配 error 或 ERROR(-E 下 | 不需要转义)
grep -E "error|ERROR" log.txt

# 匹配 一个或多个数字
grep -E "[0-9]+" file.txt

# 匹配 可选前缀 + hello:如 hello、xhello
grep -E "x?hello" file.txt

注意:不加 -E 时,+?| 在基本正则里要么没有,要么要反斜杠(如 +|),建议需要时直接用 grep -E

5.6 词边界 -w(整词)

-w 要求模式是“整词”:前后必须是非字母数字下划线(或行首/行尾)。

# 只匹配独立单词 "root",不匹配 "rooter"、"myroot"
grep -w "root" /etc/passwd

5.7 只输出“匹配到的部分”:-o

-o 只打印匹配到的字符串本身,一行里多次匹配会多行输出。

# 只输出匹配到的邮箱(假设模式写对了)
grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}" file.txt

六、多文件与递归

6.1 多个文件

在多个文件里搜,grep 会在每行前加上文件名(用 -h 可去掉文件名):

grep "error" log1.txt log2.txt log3.txt
# 输出示例:
# log1.txt:2024-01-01 10:00 error connection refused
# log2.txt:line 5: error ...

6.2 递归目录:-r、-R

在目录及其子目录下所有文件里搜索:

grep -r "function_name" ./src
grep -rn "TODO" .    # -n 带行号

常用组合:

需求 命令示例
递归 + 行号 grep -rn "pattern" 目录
递归 + 忽略大小写 grep -ri "pattern" 目录
只显示文件名 grep -rl "pattern" 目录
排除二进制(少误报) grep -rI "pattern" 目录(-I 忽略二进制)

6.3 排除/只搜某类文件(需配合 find 或 –include)

grep 自身没有“只搜 .c 文件”的选项,可配合 find

# 只在 .c 和 .h 文件里搜
find . -name "*.c" -o -name "*.h" | xargs grep "main"
# 或
grep -r "main" --include="*.c" --include="*.h" .

–include–exclude(GNU grep):

grep -r "config" --include="*.conf" .
grep -r "debug" --exclude="*.log" .

七、输入来源:文件 vs 标准输入

7.1 从文件读

grep "hello" file.txt
grep "hello" file1.txt file2.txt

7.2 从管道来(标准输入)

前一个命令的标准输出作为 grep 的输入:

cat file.txt | grep "hello"
ls -l | grep ".txt$"
ps aux | grep nginx
echo -e "anbnc" | grep "b"

注意:用管道时不要写文件名,写了文件名 grep 会去读文件,而不是管道的输出:

# 正确:grep 从管道读
cat file.txt | grep "hello"

# 错误理解:grep 不会从 cat 读,而是直接打开 file.txt(这里结果碰巧一样)
cat file.txt | grep "hello" file.txt

八、退出码(脚本里判断是否匹配)

  • 匹配到至少一行:退出码 0
  • 没匹配到:退出码 1
  • 出错(如文件不存在):退出码 2

配合 -q(不输出,只根据是否匹配设退出码):

if grep -q "success" result.txt; then
  echo "找到了 success"
else
  echo "没找到"
fi

九、彩色高亮:–color

让匹配到的字符串在终端里高亮(很多系统已默认打开):

grep --color=auto "error" log.txt
# 或
grep --color "error" log.txt

auto 表示“输出到终端就高亮,输出到文件或管道就不带颜色码”。


十、实用示例汇总

10.1 在日志里找错误

grep -i "error" /var/log/syslog
grep -in "error|exception|fail" app.log
grep -C 2 "error" app.log

10.2 排除注释和空行(看“有效配置”)

grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"

10.3 在代码里找函数/字符串

grep -rn "main" --include="*.c" --include="*.h" .
grep -r "TODO|FIXME" ./src

10.4 看某用户/某进程

grep "zhangsan" /etc/passwd
ps aux | grep nginx

10.5 只统计出现次数

grep -c "error" log.txt

10.6 整词匹配,避免误匹配

grep -w "root" file.txt

10.7 静默判断(脚本里)

grep -q "ok" status.txt && echo "成功" || echo "失败"

10.8 匹配 IP(简单示例,不严谨)

grep -E "[0-9]+.[0-9]+.[0-9]+.[0-9]+" file.txt

十一、与 egrep、fgrep 的关系

  • egrep:等价于 grep -E(扩展正则)。
  • fgrep:等价于 grep -F(固定字符串,不把模式当正则,特殊字符不当元字符)。

建议:直接记 grep -Egrep -F,不用记 egrep/fgrep。

# 模式里有大量 . * 等,不想当正则,就当普通字符搜
grep -F "file.*.txt" list.txt

十二、常见注意点

  1. 模式里有空格或特殊字符:用引号包起来,如 grep "hello world" file.txt
  2. 匹配反斜杠:要写 \,在引号里也可能要 \\,视 shell 和引号而定。
  3. 二进制文件:grep 会尝试匹配二进制,可能刷屏乱码;用 -I(或 -binary-files=without-match)跳过二进制。
  4. 大文件/大量文件:递归时用 –include 缩小范围,避免搜到无关大文件。

十三、选项速查表

选项 含义
-i 忽略大小写
-n 显示行号
-v 反向(不包含模式的行)
-c 只显示匹配行数
-l 只显示有匹配的文件名
-L 只显示无匹配的文件名
-r / -R 递归目录
-w 整词匹配
-x 整行匹配
-A n 匹配行后 n 行
-B n 匹配行前 n 行
-C n 匹配行前后各 n 行
-E 扩展正则
-F 固定字符串(不解释正则)
-o 只输出匹配到的部分
-q 安静模式(只设退出码)
-h 多文件时不输出文件名
-H 强制输出文件名
-I 忽略二进制文件
--color=auto 匹配高亮
--include=GLOB 只搜匹配 GLOB 的文件
--exclude=GLOB 排除匹配 GLOB 的文件

十四、小结

  • grep 在文本中按模式查找,打印包含该模式的行;可来自文件或管道。
  • 必会选项-i-n-v-c-l-r-w-A/-B/-C-E-q
  • 正则.*^$[ ][^ ];用 -E 时可用 +?|()
  • 脚本里-q 配合退出码判断是否匹配;-l 看哪些文件有匹配;-r 递归目录。

多在实际文件里练几遍:单文件、多文件、管道、递归、-v 排除、-C 看上下文,很快就能熟练。若你已有 Linux文件与目录管理.md,可和其中的“在文件内容里搜索:grep”一节对照看。


文档以 GNU grep 为准;BSD/macOS 自带 grep 部分选项可能略有差异。

发表评论