我是靠谱客的博主 认真身影,最近开发中收集的这篇文章主要介绍一份资深程序员的 grep 笔记,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本文原创发布于微信公众号“洛奇看世界”

网上搜索 grep 的结果基本上都是一些跟运维相关的操作,并不适用于阅读代码。

当你不想使用复杂的代码阅读工具时,快速查找代码,使用 grep 非常方便。

这里跟大家分享一下我的 grep 笔记。

这个 grep 笔记一开始比较简单,但随着各种操作的需要,出现了新的知识点,然后不断迭代,几年后差不多就是现在这个样子。

懒得整理了,除了在第三部分临时增加了两个例子之外,真的就是我自己的 grep 笔记。

本文主要包含 3 个部分:

  • 第一部分总结了 grep 命令的一些注意事项;
  • 第二部分汇总了 grep 命令的多种选项用法;
  • 第三部分总结我用 grep 看代码用得最多的方法;

除了用于阅读代码之外,平时管理服务器也经常用 grep 命令,所以对各个命令常用的场景做了标记,包括看代码常用运维常用两种。

1. grep 的命令格式

# grep [选项] 搜索模式 [文件和目录列表]
grep [OPTION]... PATTERN [FILE]...

1.1 注意事项

  • 引号问题

建议: 三剑客 grep,sedawk 的模式字符串都使用单引号 ‘’ 包含

搜索的模式 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 操作会返回其状态,对于一般函数来讲,就是函数内部的 returnexit 等。
返回值通过变量 $? 获取。

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 的 devicebuild 目录下搜索命令行参数的设置和使用,但是具体名字不记得了,那就搜索 CMDLINE 字符串吧。

devicebuild 目录中搜索字符串 “CMDLINE”:

  • 搜索 devicebuild 目录
  • 不想搜索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 笔记所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部