概述
本文原创发布于微信公众号“洛奇看世界”
网上搜索 grep 的结果基本上都是一些跟运维相关的操作,并不适用于阅读代码。
当你不想使用复杂的代码阅读工具时,快速查找代码,使用 grep 非常方便。
这里跟大家分享一下我的 grep 笔记。
这个 grep 笔记一开始比较简单,但随着各种操作的需要,出现了新的知识点,然后不断迭代,几年后差不多就是现在这个样子。
懒得整理了,除了在第三部分临时增加了两个例子之外,真的就是我自己的 grep 笔记。
本文主要包含 3 个部分:
- 第一部分总结了 grep 命令的一些注意事项;
- 第二部分汇总了 grep 命令的多种选项用法;
- 第三部分总结我用 grep 看代码用得最多的方法;
除了用于阅读代码之外,平时管理服务器也经常用 grep 命令,所以对各个命令常用的场景做了标记,包括看代码常用和运维常用两种。
1. grep
的命令格式
# grep [选项] 搜索模式 [文件和目录列表]
grep [OPTION]... PATTERN [FILE]...
1.1 注意事项
- 引号问题
建议: 三剑客 grep
,sed
和 awk
的模式字符串都使用单引号 ‘’ 包含
搜索的模式 PATTERN
用单引号 ''
或双引号 ""
包含起来,避免被解释为文件。
例如搜索 “bash shell” 字符串,如果使用:
$ grep bash shell /etc/test
会被理解为从shell
和/etc/test
两个文件中查找bash
字符串,所以应该使用引号包含:
$ grep 'bash shell' /etc/test
$ grep "bash shell" /etc/test
这个引号最容易出问题还是在
find
命令中。
- 搜索字符串中带有连字符
-
问题
如果搜索的 PATTERN
中带有连字符 -
,使用反斜线 将其转义,如: 从
grep
命令的帮助信息中查找-c
选项的信息:
$ grep --help | grep '-c'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
这个命令中,前半部分 grep --help
执行是正确的,可以用其它命令 tar --help | grep '-c'
测试。
但是后半部分 grep '-c'
操作出错了,因为这里将 -c
字符串当做选项使用了,使用反斜线转义-
字符解决(下面每一行的结果中都包含了 -c
字符串):
$ grep --help | grep '-c'
-i, --ignore-case ignore case distinctions
-m, --max-count=NUM stop after NUM matches
-c, --count print only a count of matching lines per FILE
-B, --before-context=NUM print NUM lines of leading context
-A, --after-context=NUM print NUM lines of trailing context
-C, --context=NUM print NUM lines of output context
-NUM same as --context=NUM
--color[=WHEN],
--colour[=WHEN] use markers to highlight the matching strings;
1.2 输出值和返回值
什么是函数的输出值和返回值,二者有什么区别?
- 输出值
grep
操作的输出内容作为输出值, 对于一般函数来讲,就是函数内部的 echo
输出。
所以输出值大多数时候是终端查找时用于显示, shell程序中更关心返回值, 用于判断是否存在匹配模式。
如:
$ grep 'root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
$ item=$(grep 'root' /etc/passwd)
$ echo $?
0
$ echo $item
root:x:0:0:root:/root:/bin/bash
这里 grep 'root' /etc/passwd
的输出内容为 root:x:0:0:root:/root:/bin/bash
。
所以变量 $item
获取的输出值为 root:x:0:0:root:/root:/bin/bash
- 返回值
返回值一般都是给shell程序使用, 如果指向在终端使用grep查找, 则不用关心其返回值)
grep
操作会返回其状态,对于一般函数来讲,就是函数内部的 return
和 exit
等。
返回值通过变量 $?
获取。
grep
的man手册中是这样定义返回值的:
EXIT STATUS
The exit status is 0 if selected lines are found, and 1 if not found.
If an error occurred the exit status is 2.
(Note: POSIX error handling code should check for '2' or greater.)
退出状态如下:
- 找到匹配内容返回0,
- 没有查找到匹配内容返回1,
- 失败返回2
# 1. 查找root成功,返回0
$ grep -q "root" /etc/passwd; echo $?
0
# 2. 没有找到匹配内容,返回1
$ grep -q "rocky" /etc/passwd; echo $?
1
# 3. 查找失败,返回2
$ grep -q "rocky" /etc/password; echo $?
grep: /etc/password: No such file or directory
2
$ grep -q -s "rocky" /etc/password; echo $?
2
# 选项:
# "-q"选项,抑制正常输出(安静查找)
# "-s"选项, 抑制错误消息
$ grep --help | grep -Ew "-[s|q]"
-s, --no-messages suppress error messages
-q, --quiet, --silent suppress all normal output
if any error occurs and -q is not given, the exit status is 2.
通常用于 shell 脚本中不获取输出,仅获取其操作结果返回值的情况,如:
# 在 /etc/nsswitch.conf 文件中搜索 "automount" 开始的行
if ! grep -q "^automount" /etc/nsswitch.conf; then
sed -i "s/^netgroup:.*/&nautomount: files nis/" /etc/nsswitch.conf
fi
这里如果在 /etc/nsswitch.conf
中搜索到 ^automount
的匹配内容,则 grep
操作返回 0。条件语句 ! grep -q "/etc/auto.direct" /etc/nsswitch.conf
的结果为真,条件成立,执行随后的语句。
另一个例子:
if [ "$CONF_NFS" != "0" ]; then
if ! grep -q "^/local/git" /etc/exports; then
echo "/local/git $STBSITE-*(ro,sync,root_squash,mp=/local,no_subtree_check)" >> /etc/exports
fi
fi
2. grep
的常用选项
2.1 选项 -n
,显示行号
看代码常用
# 在 /etc/passwd, /etc/group 文件中搜索 root 字符串
$ grep -n "root" /etc/{passwd,group}
/etc/passwd:1:root:x:0:0:root:/root:/bin/bash
/etc/group:1:root:x:0:
2.2 选项 -r/R
,递归查找
看代码常用
如果指定了目录,默认仅在指定目录下查找,使用 -r/R
后会递归在所有子目录下查找。
#
# 'tree . -l'选项列举符号链接文件和目录
#
$ tree . -l
.
├── df.txt
├── gnu-utils -> ../gnu-utils
│ ├── info-find.txt
│ ├── info-man.txt
│ ├── info-sed.txt
│ ├── info-xargs.txt
│ ├── man-find.txt
│ ├── man-grep.txt
│ ├── man-help.txt
│ ├── man-man.txt
│ ├── man-sed.txt
│ └── man-xargs.txt
├── info-grep.txt
├── man-grep.txt
└── man-tree.txt
1 directory, 14 files
$
# 这里当前目录的"gnu-utils"连接到"../gnu-utils"
#
# '-r'递归搜索,但不跟踪符号链接文件和目录
#
$ grep -rl "grep" .
./info-grep.txt
./man-grep.txt
$
#
# '-R'递归搜索,跟踪符号链接文件和目录
# 'gnu-utils'为符号链接目录
#
$ grep -Rl "grep" .
./info-grep.txt
./man-grep.txt
./gnu-utils/info-sed.txt
./gnu-utils/info-xargs.txt
./gnu-utils/man-grep.txt
./gnu-utils/man-sed.txt
./gnu-utils/man-find.txt
-r
和 -R
的区别:
-r
,递归查找-R
,递归查找,并查找符号链接(symlinks
)文件和目录。
3. 选项 -i
,忽略大小写
看代码常用
- 默认搜索会区分大小写
$ grep --help | grep -w "-c"
-c, --count print only a count of matching lines per FILE
- 带
-i
不区分大小写
$ grep --help | grep -w -i "-c"
-c, --count print only a count of matching lines per FILE
-C, --context=NUM print NUM lines of output context
4. 选项 -w
,匹配完整单词
看代码常用
- 默认会搜索到很多包含
"-c"
内容的字符串
$ grep --help | grep "-c"
-i, --ignore-case ignore case distinctions
-m, --max-count=NUM stop after NUM matches
-c, --count print only a count of matching lines per FILE
-B, --before-context=NUM print NUM lines of leading context
-A, --after-context=NUM print NUM lines of trailing context
-C, --context=NUM print NUM lines of output context
-NUM same as --context=NUM
--color[=WHEN],
--colour[=WHEN] use markers to highlight the matching strings;
- 带
-w
选项精确匹配"-c"
字符串:
$ grep --help | grep -w "-c"
-c, --count print only a count of matching lines per FILE
5. 选项 -A/B/C
,显示上下文
看代码常用
-A
, after,在搜索结果中显示匹配点后面的若干行-B
, before,在搜索结果中显示匹配点前面的若干行-C
, context,在搜索结果中显示匹配点前面和后面的若干行
在查看代码时,除了搜索结果,还经常想看下匹配结果的上下文时,特别好用。
6. 选项 -c
,显示匹配数量
运维常用
- 默认显示匹配的所有内容
# 查找ip地址
$ grep -E "([0-9]{1,3}.){3}[0-9]{1,3}" /etc/network/interfaces
address 10.148.7.17
netmask 255.255.254.0
network 10.148.6.0
broadcast 10.148.7.255
gateway 10.148.6.1
dns-nameservers 192.19.189.30 192.19.189.20 192.19.189.10
- 带
-c
选项仅显示匹配的数量
# 查找ip地址
$ grep -E -c "([0-9]{1,3}.){3}[0-9]{1,3}" /etc/network/interfaces
6
- 代码片段
# 如果搜索的匹配数量不为0,则执行后续操作
if [ 0$(grep -c "^rsnapshot" /etc/auto.projects) -eq 0 ]; then
echo "rsnapshot -fstype=nfs,ro,nobind $BAKHOST:$BAKPATH/rsnapshot" >> /etc/auto.projects
fi
7. 选项 --exclude/--exclude-dir
,排除搜索的文件和路径
看代码常用
- 默认搜索时会查找所有文件和目录
bolt-android.git$ grep -rnwl sec_read_otp_bit .
./security/7445e0/bsl-lib.a
./security/verify_ssbl.c
...
./security/bfw_load.c
./ssbl/ui/ui_secboot.c
./objs/7260b0/security/bsp_utils.i
...
./fsbl/fsbl-hacks.c
./fsbl/fsbl-main.c
./fsbl/fsbl-sec.c
- 带
--exclude=GLOB
选项,指定不进行搜索的文件类型,GLOB为通配符
# 使用多个 --exclude 进行排除,命令太长了
$ grep -rnwl sec_read_otp_bit . --exclude=*.s --exclude=*.i --exclude=*.o --exclude=*.a
# 使用单个 --exclude 进行排除
# 例1. 查找包含字符串 sec_read_otp_bit 的文件(排除编译生成文件和库文件)
$ grep -rnwl sec_read_otp_bit . --exclude=*.{s,i,o,a}
# 例2. 查找字符串FIRST(带有FIRST的宏,但不在.h和.c文件中搜索)
$ grep -rn FIRST . --exclude={*.c,*.h}
- 带
--exclude-dir=DIR
选项,指定不进行搜索的目录
# 使用多个 --exclude-dir 进行排除
$ grep -rnwl sec_read_otp_bit . --exclude-dir=objs --exclude-dir=security
# 使用单个 --exclude-dir 进行排除
$ grep -rnwl sec_read_otp_bit . --exclude-dir={objs,security}
8. 选项 --include
, 指定搜索的文件
看代码常用
-
默认会在所有文件中搜索
-
带
--include=GLOB
选项,在指定的文件中搜索
# 使用多个--include进行指定
$ grep -rnwl sec_read_otp_bit . --include=*.c --include=*.s
# 使用单个--include和通配符进行指定
$ grep -rnwl sec_read_otp_bit . --include=*.{c,s}
千万不要问:
- 排除搜索时有
--exclude=GLOB
和--exclude-dir=DIR
,- 指定搜索时有
--include=GLOB
,- 为什么没有
--include-dir=DIR
?因为直接在
"grep [OPTION] PATTERN DIR ..."
时直接指定一个或多个DIR就可以了~~
9. 选项 -I
,不搜索二进制文件
看代码有时用
默认会搜索所有文件,将二进制文件也当做text进行搜索。
如果指定-I
或--binary-files=without-match
选项,则二进制文件即使包含相应字符串,也当做不包含该内容处理。
$ grep -rnwlI sec_read_otp_bit .
./security/verify_ssbl.c
./security/boot_defines.h
...
./objs/7260b0/security/bsp_utils.i
./objs/7260b0/security/verify_ssbl.i
./objs/7260b0/security/scramble.s
...
这里搜索字符串sec_read_otp_bit
时,不再从*.{a,o,bin}
文件中搜索
10. 选项 -v
, 反向查找
运维常用
- 默认显示匹配内容的行
# 搜索"#"开始的行(注释行)
$ grep "^#" /etc/passwd
# adminbse:x:200:200:Admin Bse,,,:/home/adminbse:/bin/bash
# 2016-07-29 adminbse jjwong - Change adminbse to adm(4) group
- 带
-v
选项显示不匹配内容的行
# 搜索不以"#"字符开始的行
$ grep -v "^#" /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...
11. 选项 -q
,静默查找
运维常用
- 默认显示输出结果
$ grep -rs "^root" /etc
/etc/lxctl/lxctl.yaml:root:
/etc/services:rootd 1094/tcp
/etc/services:rootd 1094/udp
/etc/group:root:x:0:
/etc/postfix/virtual:root root@localhost
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/newt/palette.ubuntu:root=,magenta
/etc/newt/palette.ubuntu:roottext=,magenta
- 带
-q
不显示搜索匹配结果
$ grep -rq "^root" /etc
$ echo $?
0
通常用于shell脚本中不获取输出,仅获取其操作结果返回值的情况,如:
# 在/etc/fstab文件中搜索"/etc/auto.direct"
if ! grep -q "/etc/auto.direct" /etc/fstab; then
echo -e "n# $TODAY $AUTHOR - Use /etc/auto.direct for NFS mounts" >> /etc/fstab
fi
这里如果在/etc/fstab
中搜索到/etc/auto.direct
的匹配内容,则grep
操作返回0。条件语句 ! grep -q "/etc/auto.direct" /etc/fstab
的结果为真,条件成立,执行随后的语句。
另一个例子:
if ! grep -q "guyongqiangx" /etc/yp.conf; then
NISLIST="nis2.she.guyongqiangx.com nis1.she.guyongqiangx.com"
echo -e "n# $TODAY $AUTHOR - NIS servers" >> /etc/yp.conf
echo -e "n# $TODAY $AUTHOR - NIS servers" >> /etc/hosts
for NISN in $NISLIST; do
echo "domain $(cat /etc/defaultdomain) server $NISN" >> /etc/yp.conf
NISIP=$(host $NISN | grep -o "has address .*" | cut -d' ' -f3)
if [ ! -z $NISIP ]; then
echo -e "$NISIPt$NISN" >> /etc/hosts
else
echo -e "# 0.1.2.3t$NISN" >> /etc/hosts
fi
done
fi
fi
使用 grep -c
进行操作的例子(这里获取的不再是 grep
执行的返回值,而是获取 grep
操作获取的内容):
# 在/etc/auto.projects中搜索"^rsnapshot"
$ grep "^rsnapshot" /etc/auto.projects
rsnapshot -fstype=nfs,ro,nobind stbszx-bak-1:/local/backups/rsnapshot
# 在/etc/auto.projects中搜索"^rsnapshot"匹配的数量
$ grep -c "^rsnapshot" /etc/auto.projects
1
# 0与搜索结果合并,构成数字01
# $(grep -c "^rsnapshot" /etc/auto.projects)获取操作返回的内容
$ echo 0$(grep -c "^rsnapshot" /etc/auto.projects)
01
# 如果搜索的匹配数量不为0,则执行后续操作
if [ 0$(grep -c "^rsnapshot" /etc/auto.projects) -eq 0 ]; then
echo "rsnapshot -fstype=nfs,ro,nobind $BAKHOST:$BAKPATH/rsnapshot" >> /etc/auto.projects
fi
12. 选项 -s
,抑制错误信息
运维常用
- 默认显示错误信息
$ grep -r rocky /etc/
grep: /etc/gshadow: Permission denied
/etc/subgid:rocky:165536:65536
grep: /etc/security/opasswd: Permission denied
grep: /etc/default/cacerts: Permission denied
...
grep: /etc/group-: Permission denied
grep: /etc/polkit-1/localauthority: Permission denied
- 带
-s
抑制错误信息
$ grep -rs rocky /etc/
/etc/subgid:rocky:165536:65536
/etc/subuid:rocky:165536:65536
/etc/passwd:rocky:x:1001:1001:rocky:/home/rocky:/bin/bash
/etc/group:sudo:x:27:ygu,rocky
/etc/group:rocky:x:1001:rocky
相当于将错误输出重定向到/dev/null
,即2>/dev/null
$ grep -r rocky /etc/ 2>/dev/null
/etc/subgid:rocky:165536:65536
/etc/subuid:rocky:165536:65536
/etc/passwd:rocky:x:1001:1001:rocky:/home/rocky:/bin/bash
/etc/group:sudo:x:27:ygu,rocky
/etc/group:rocky:x:1001:rocky
13. 选项 -h
,搜索输出中不显示文件名
运维常用
- 单个文件搜索时,搜索结果中不显示文件名,只有在多文件搜索是才会存在文件名:
# 单个文件搜索
$ grep -s "^root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
# 多个文件搜索
$ grep -s "^root" /etc/passwd /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/group:root:x:0:
# 目录搜索
$ grep -rs "^root" /etc
/etc/lxctl/lxctl.yaml:root:
/etc/services:rootd 1094/tcp
/etc/services:rootd 1094/udp
/etc/group:root:x:0:
/etc/postfix/virtual:root root@localhost
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/newt/palette.ubuntu:root=,magenta
/etc/newt/palette.ubuntu:roottext=,magenta
- 默认搜索结果中显示文件名
$ grep -rs "^root" /etc
/etc/lxctl/lxctl.yaml:root:
/etc/services:rootd 1094/tcp
/etc/services:rootd 1094/udp
/etc/group:root:x:0:
/etc/postfix/virtual:root root@localhost
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/newt/palette.ubuntu:root=,magenta
/etc/newt/palette.ubuntu:roottext=,magenta
- 带
-h
选项的结果中不显示文件名
$ grep -rsh "^root" /etc
root:
rootd 1094/tcp
rootd 1094/udp
root:x:0:
root root@localhost
root:x:0:0:root:/root:/bin/bash
root=,magenta
roottext=,magenta
14. 选项 -o
,只显示匹配内容
运维常用
- 默认显示所有匹配的行
# 查找ip地址
$ grep -E "([0-9]{1,3}.){3}[0-9]{1,3}" /etc/network/interfaces
address 10.148.7.17
netmask 255.255.254.0
network 10.148.6.0
broadcast 10.148.7.255
gateway 10.148.6.1
dns-nameservers 192.19.189.30 192.19.189.20 192.19.189.10
- 带
-o
选项仅显示匹配的内容
# 查找ip地址
$ grep -E -o "([0-9]{1,3}.){3}[0-9]{1,3}" /etc/network/interfaces
10.148.7.17
255.255.254.0
10.148.6.0
10.148.7.255
10.148.6.1
192.19.189.30
192.19.189.20
192.19.189.10
示例2:
Android 的 manifest 文件中有很多 project,每个 project 都有一个 groups 选项,显示所有的 gropus 选项:
...
<project groups="device,yukawa,pdk" name="device/amlogic/yukawa" revision="e6bdb83eb57cd9fa46d827950b4d52ffe8e101d3"/>
...
<project groups="pdk-cw-fs,pdk" name="device/common" revision="9d2a0d0c3aab8b698669bad9810bc52ac7f76dfb"/>
<project groups="pdk" name="device/generic/arm64" revision="b2aea8576e3928e9add8b616740e56c1c5a811d2"/>
...
查找所 有groups 匹配的字符串(这里包含了 “groups=” 字符串本身):
$ grep -oE "groups="[^"]*?"" .repo/manifest.xml | sort -u | uniq
groups="adt-infra,cts,developers,motodev,pdk,tools,tradefed"
groups="adt-infra,notdefault,pdk-fs"
groups="apps_nfc,pdk-fs"
groups="apps_se,pdk-fs"
groups="apps_stk,pdk-fs"
...
这里只显示匹配内容有什么用呢?这里可以获取匹配的内容做进一步处理,例如:
# 1. 通过grep操作提取子域名sub-domain
# 'grep -Po "(?<=^searchs).+" /etc/resolv.conf', '-P'指定使用perl格式的正则表达式
SUBDOMAINS="$(grep -Po "(?<=^searchs).+" /etc/resolv.conf) guyongqiangx.net guyongqiangx.com $(hostname -d)"
[ -n "$SUBDOMAINS" ] && for SUBDN in $SUBDOMAINS; do
sed -i -r "/^s+dns-search.*$SUBDN/! s/^s+dns-searchs+/&$SUBDN /" /etc/network/interfaces
if [ -d /etc/netplan ]; then
sed -i -r "/^s+search:.*$SUBDN/! s/^s+search:.*[s*/&$SUBDN, /" /etc/netplan/7[0-9]*.yaml
netplan --debug generate
fi
done
# 2. 通过grep操作提取uid=1000的用户名,然后将其替换为adminbse
# 'grep -Po "^[[:alnum:]-_]+(?=:x:1000:)" /etc/passwd', '-P'指定使用perl格式的正则表达式
USER1000="$(grep -Po "^[[:alnum:]-_]+(?=:x:1000:)" /etc/passwd)" # delete Ubuntu's first UID 1000
if [ -n "$USER1000" -a "$USER1000" != "adminbse" ]; then
sed -i "s/$USER1000/adminbse/" /etc/group
(sleep 25; deluser --remove-home $USER1000; delgroup $USER1000) & # delay until script ends so we don't get locked out
fi
15. 选项 -l
,显示包含匹配内容的文件名
运维常用
- 默认显示所有匹配的内容,并在每一处匹配内容前显示文件名
$ grep -s "^root" /etc/*
/etc/group:root:x:0:
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/services:rootd 1094/tcp
/etc/services:rootd 1094/udp
- 带
-l
选项仅显示包含匹配内容的文件名
$ grep -sl "^root" /etc/*
/etc/group
/etc/passwd
/etc/services
16. 选项 -L
,显示不匹配内容的文件名
运维常用
- 显示不包含匹配内容的文件名
$ grep -sL "^root" /etc/*
/etc/ImageMagick
/etc/X11
/etc/acpi
/etc/adduser.conf
/etc/aliases
/etc/aliases.db
/etc/alternatives
3. 阅读代码时常用的 grep
操作
总结上一节中的各种选项,以下选项在阅读代码时最常用:
-i
,搜索结果是否忽略大小写-w
,搜索结果是否匹配完整单词-n
,搜索结果是否显示行号-C
,搜索结果是否显示匹配行的上下文--exclude
,不需要搜索的文件--exclude-dir
,不需要搜索的文件夹
千万不要想着为啥不包含正则表达式选项,其实我读代码使用正则表达式的情况特别特别少,一年也不需要几次,所以不用去记忆那些复杂的正则表达式规则。
大概 80% 的时间都是使用下面这三条 grep
命令搜索代码:
- 忽略大小写,可以匹配部分
$ grep -Rni "keyword" dir/
- 忽略大小写,匹配完整单词
$ grep -Rni "keyword" dir/
- 忽略大小写,排除部分文件(*.s, *.a)和目录(out 和 gen)
$ grep -rni "keyword" dir/ --exlude=*.{s,a} --exlude-dir={out,gen}
阅读代码,准备搜索某个主题相关代码时,换位思考,想象你就是写代码的那个程序员,你会在代码中使用什么样的词?
然后就尝试用这个关键词使用 grep
进行搜索。这种方法非常好用,我在 《读代码,没有头绪怎么办?》 介绍过,希望你能喜欢这种思考方法。
下面列举几个常用的场景。
3.1 搜索字符串 “dynamic”
例如,想在 Android 的 build 目录查找动态分区相关的宏定义,但一时又不知道要用什么关键字,但动态分区,肯定和单词 dynamic
有关,于是可以在 build
目录下先搜索下所有带有 dynamic
的字符串。
因为只希望搜索 Makefile 相关的文件,所以这里:
- 排除不相关的其它文件
*.{py,go,css,js,html}
因为有些脚本文件做了链接,搜索结果可能会出现重复,我们这里:
- 使用
-r
选项不跟踪链接文件。
(如果使用 -R
选项则会搜索符号链接文件的内容)
所以执行的命令如下:
$ grep -rni "dynamic" build/ --exclude=*.{py,go,css,js,html}
3.2 搜索字符串"V2"
在当前项目的 makefile (包括Makefile, makefile, *.mk, *.build, *.inc
等后缀)和一些脚本中搜索 V2
字符串。(secv2
)
在当前目录和子目录中搜索字符串 “V2
”:
- 仅搜索非代码文件
*.{h,c,cpp}
- 不在
obj.*
的目录中搜索 - 不搜索二进制文件
$ grep -rnI V2 . --exclude=*.{h,c,cpp} --exclude-dir=obj.*
3.3 搜索字符串 “CMDLINE”
想知道命令行参数在 android 下是如何设置并起作用的?
在 Android 的 device
和 build
目录下搜索命令行参数的设置和使用,但是具体名字不记得了,那就搜索 CMDLINE 字符串吧。
在 device
和 build
目录中搜索字符串 “CMDLINE
”:
- 搜索
device
和build
目录 - 不想搜索
device/google
目录
$ grep -rn CMDLINE device build --exclude-dir=google
3.4 搜索字符串 “retrofit”
在 Android 研究动态分区时,使用了一个字符串 “retrofit”,我想在 device
目录下查看各厂商对 “retrofit” 字符串相关的宏定义和引用,也想看下这些地方的上下文代码。
- 搜索
device
目录 - 不搜索
.git
目录 - 所有不分大小写的包含 “retrofit” 的字符串
- 查看匹配点的前后 5 行代码
$ grep -Rni RETROFIT device/ --exclude-dir=.git -C 5
关于
grep
工具,如果你有什么好的用法,欢迎留言区或微信交流。
关于 grep 工具,如果你有什么好的用法,欢迎留言区或微信交流。
4. 近期文章
代码阅读
- 读代码,没有文档怎么办?
- 读代码,如何精准定位?
- 读代码,没有头绪怎么办?
- 读代码,多用用这种方式
调试
- 程序查错,一种排查问题的通用方法
- 程序查错,一类常见错误的处理思路
- 程序查错,第一件事要做什么?
其它
- 二八法则,致每一个前行路上的你
- 遇到有人装 X 显摆怎么办?
5. 其它
洛奇自己维护了一个公众号“洛奇看世界”,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:
最后
以上就是认真身影为你收集整理的一份资深程序员的 grep 笔记的全部内容,希望文章能够帮你解决一份资深程序员的 grep 笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复