使⽤grep 搜索代码的⼏个⽰例作为基于windows系统⼯作的攻城狮,每天必须⽤sourceinsight ,这⼯具确实好⽤,关键词和语法着⾊,上下⽂联想,代码⾃动补全,但是也经常发现有些不太⽅便的地⽅。例如:操作前需要先建⽴⼯程,这也没什么,但是如果只想临时在某个代码包⾥查符号变量什么的,也得需要先创建⼯程;对于代码量很⼤的项⽬,如Android,⼯程的创建和解析都很⿇烦;还有就是对⼆进制搜索⽀持不好,对搜索的匹配也很有限。好吧,刚发现sourceinsight 还⽀持正则表达式搜索,这个功能什么时候出现的?搜索代码,或者是查关键词,除了sourceinsight ,那就应该是grep 了。 可是度娘⼀下”grep “看看你能收到什么?⼤多数都是”grep命令详解”,“grep命令和参数的⽤法”,要不就是“grep和正则表达式”,然后点进去就是给你罗列⼀⼤堆“grep”的选项,要不就是罗列⼀⼤堆正则表达式语法,是罗列,罗列啊~我TM不想知
道“grep”的⼀⼤堆选项,要你说,运⾏“man grep”详细到⼗万⼋千⾥去了,我也不想去研究正则表达式的各种语法,我只想知道如何解决我我遇到的实际问题。
好吧,搜索了半天,也还是解决不了问题,最好⽼⽼实实“man grep”去答案吧。下⾯,从码农读代码的⾓度,总结下我最常⽤的grep ⽅式,也欢迎⼤家交流下grep 的⼀些⾼级⽤法。
读代码时的查通常⽐较简单,就是想知道某些符号在哪个⽂件定义或在哪些地⽅被引⽤,都是⼀些明确的符号,很少需要模糊查,所以⽤到复杂正则表达式的机会很少。免不了啰嗦⼀下,“grep”的常⽤的⼏个选项:
-r ,递归查
-n ,搜索结果显⽰⾏号
-i ,忽略⼤⼩写
-v ,反向匹配
-w ,匹配整个单词
-E ,匹配扩展的正则表达式这⾥以u-boot-2016.09代码为例,进⾏memcpy 查操作。
find查命令的使用1. 递归查并显⽰⾏号
这个是最基本的查了。在当前⽬录查可以使⽤:不指定⽬录:”grep -rn memcpy ”⽤”.“指定当前⽬录:”grep -rn memcpy .”
其实这两者查结果⼀样,但在输出格式上是有区别的,具体留给你去⽐较好了。
2. 查不区分⼤⼩写选项”-i “或略⼤⼩写,这样除了匹配“memcpy ”外,还可以匹配⼀些宏定义如”MEMCPY “和”Memcpy “等,如:ygu@guyongqiangx :u-boot-2016.09$ grep -rn memcpy
1ygu@guyongqiangx :u-boot-2016.09$ grep -rni memcpy
1
3. 排除指定⽂件的搜索结果
搜索结果的第⼀列会显⽰搜索结果位于哪个⽂件中,所以可以通过对搜索结果第⼀列的过滤来排除指定⽂件。例如:编译时⽣成的*.o.cmd ⽂件中带了很多包含memcpy.h 的⾏,如:可以在搜索结果中⽤反向匹配”-v “排除*.o.cmd ⽂件的匹配:如果想排除多个⽣成⽂件中的匹配,包括”*.o.cmd ,*.s.cmd ,*.o ,*.map “等,有两种⽅式:使⽤多个-v 依次对上⼀次的结果进⾏反向匹配:使⽤-Ev ⼀次进⾏多个反向匹配搜索:由于这⾥使⽤了正则表达式”-E “,所以需要⽤”\“将”.“字符进⾏转义另外,也可以使⽤”--exclude=GLOB “来指定排除某些格式的⽂件,如不在“*.cmd ”,“*.o ”和“*.map ”中搜索:...include/malloc.h:351:#define HAVE_MEMCPY include/malloc.h:353:#ifndef USE_MEMCPY include/malloc.h:354:#ifdef HAVE_MEMCPY include/malloc.h:355:#define USE_MEMCPY 1include/malloc.h:357:#define USE_MEMCPY 0include/malloc.h:361:#if (__STD_C || defined(HAVE_MEMCPY))include/malloc.h:365:void* memcpy(void*, const void*, size_t);...board/freescale/t102xrdb/spl.c:63: /* Memcpy existing GD at CONFIG_SPL_GD_ADDR */board/freescale/t102xrdb/spl.c:64: memcpy((void *)CONFIG_SPL_GD_ADDR, (void *)gd, sizeof(g
d_t));board/freescale/t208xqds/spl.c:68: /* Memcpy existing GD at CONFIG_SPL_GD_ADDR */...
1
2
3
4
5
6
7
8
9
10
11
1213out /rpi_3_32b/drivers/input/.d :295: $(wildcard include/config/use/arch/memcpy .h )
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn memcpy | grep -v .o.cmd
1ygu@guyongqiangx:u-boot-2016.09$ grep -rn memcpy | grep -v .o.cmd | grep -v .s .cmd | grep -v .o | grep -v .map 1ygu@guyongqiangx :u-boot-2016.09$ grep -rn memcpy | grep -Ev '\.o\.cmd|\.s\.cmd|\.o|\.map'
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn --exclude=*.cmd --exclude=*.o --exclude=*.map memcpy
1
跟“--exclude=GLOB ”类似的⽤法有“--include=GLOB ”,从指定的⽂件中搜索,如只在“*.cmd ”,“*.o ”和“*.map ”中搜索:
“--include=GLOB ”在不确定某些函数是否被编译时特别有⽤。
例如,不确定函数rpi_is_serial_active 是否有被编译,那就查“*.o”⽂件是否存在这个函数符号:
显然,从结果看,这个函数是参与了编译的,否则搜索结果为空。如果想知道函数rpi_is_serial_active 最后有没有被链接使⽤,查询⽣成的u-boot*⽂件就知道了:
可见u-boot ⽂件中到了这个函数符号。
4. 不在某些指定的⽬录查memcpy
如果指定了u-boot 编译的输出⽬录,例如输出到out ,则可以直接忽略对out ⽬录的搜索,如:
忽略多个⽬录(“out”和“doc”):
5. 查精确匹配结果通常的“memcpy ”查结果中会有⼀些这样的匹配:“MCD_memcpy ”,“zmemcpy ”,“memcpyl ”,“memcpy_16”等,如果只想精确匹配整个单词,则使⽤-w 选项:
6. 查作为单词分界的结果
“作为单次分界“这个表述不太准确,例如,希望“memcpy ”的查中,只匹配“MCD_memcpy ”,“memcpy_16”,⽽不⽤匹配“zmemcpy ”,“memcpyl ”这样的结果,也就是memcpy 以⼀个完整单词的形式出现。
⼀般这种查询就需要结合正则表达式了,⽤正则表达式去匹配单词边界,例如:
关于正则表达式“(\b|_)memcpy(\b|_)”
“\b “匹配单词边界
“_“匹配单个下滑下
所以上⾯的表达式可以匹配:memcpy ,memcpy_xxx ,xxx_memcpy 和xxx_memcpy_xxx 等模式。(可能匹配的还有函数memcpy_,_memcpy 和_memcpy_)
7. 查看查结果的上下⽂
想在结果中查看匹配内容的前后⼏⾏信息,例如想看宏定义“MEMCPY ”匹配的前三⾏和后两⾏:
ygu@guyongqiangx :u-boot-2016.09$ grep -rn --include =*.cmd --include =*.o --include =*.map memcpy
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn --include =*.o rpi_is_serial_active Binary file out/rpi_3_32b/board/raspberrypi/rpi/built-in .o matches Binary file out/rpi_3_32b/board/raspberrypi/rpi/rpi.o matches
1
2
3ygu@guyongqiangx :u-boot-2016.09$ grep -rn --include =u-boot* rpi_is_serial_active Binary file out/rpi_3_32b/u-boot matches
1
2ygu@guyongqiangx :u-boot-2016.09$ grep -rn --exclude-dir=out memcpy
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn --exclude-dir=out --exclude-dir=doc memcpy
1ygu@guyongqiangx :u-boot-2016.09$ grep -rnw memcpy .
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn -E "(\b|_)memcpy(\b|_)"
1ygu@guyongqiangx :u-boot-2016.09$ grep -rn -B 3 -A 2 MEMCPY
1
选项B/A :
-B 指定显⽰匹配前(Before)的⾏数
-A 指定显⽰匹配后(After)的⾏数
8. grep 和find 配合进⾏查
find针是对⽂件级别的粗粒度查,⽽grep则对⽂件内容的细粒度搜索。
所以grep跟find命令配合,⽤grep在find的结果中进⾏搜索,能发挥更⼤的作⽤,也更⽅便。例如,我想查所有makefile 类⽂件中对CFLAGS 的设置。 makefile 类常见⽂件包括makefile ,*.mk ,*.inc 等,⽽且⽂件名还可能是⼤写的。
可以通过find命令先出makefile 类⽂件,然后再从结果中搜索CFLAGS :这⾥由于涉及到find命令,所以整个查看起来有点复杂了,也可以只⽤grep 的--include=GLOB 选项来实现:
⽐较上⾯的两个搜索结果,是⼀样的,但是有⼀点要注意:
grep 命令的--include=GLOB 模式下,⽂件名是区分⼤⼩写的,⽽且没有⽅式指定忽略⽂件名⼤⼩写
刚好这⾥搜索的Makefile 只有⾸字母⼤写的形式,⽽不存在⼩写的makefile ,所以这⾥碰巧是结果⼀致⽽已,否则需要指定更多的--include=GLOB 参数。
9. ⼀些练习
1. 在linux⽬录中查所有的*.h,并在这些⽂件中查“SYSCALL_VECTOR”
2. 在练习1的基础上,打印出所有包含”SYSCALL_VECTOR”字符串的⽂件名
grep 的选项-l 只打印匹配的⽂件名。
以上是我的⼀些grep ⽤法,欢迎交流,共同提⾼读代码的效率。ygu@guyongqiangx:u-boot-2016.09$ find . -iname Makefile -o -iname *.inc -o -iname *.mk | xargs grep -rn CFLAGS 1ygu@guyongqiangx :u-boot-2016.09$ grep -rn --include =Makefile --include =*.inc --include =*.mk CFLAGS .
1ygu@guyongqiangx :linux-3.14-1.5$ find linux -name *.h | xargs grep "SYSCALL_VECTOR"linux/arch/x86/include /asm/irq_vectors.h:#define IA32_SYSCALL_VECTOR 0x80linux/arch/x86/include /asm/irq_vectors.h:# define SYSCALL_VECTOR 0x80linux/arch/m32r/include /asm/syscall.h:#define SYSCALL_VECTOR "2"linux/arch/m32r/include /asm/syscall.h:#define SYSCALL_VECTOR_ADDRESS "0xa0"
1
2
3
4
5ygu@guyongqiangx :linux-3.14-1.5$ find linux -name *.h | xargs grep -l "SYSCALL_VECTOR" linux/arch/x86/include /asm/irq_vectors.h linux/arch/m32r/include /asm/syscall.h
1
2
3
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论