Linux进阶必学知识:grep是什么?怎么用?

系统
经常读一些介绍unix命令的文章,但是文章所举的例子普遍价值不大,这就导致了看完了文章后我们并不知道如何有效地运用这些unix命令。

经常读一些介绍unix命令的文章,但是文章所举的例子普遍价值不大,这就导致了看完了文章后我们并不知道如何有效地运用这些unix命令。

写在前面

三年前,作为面试官,我负责招聘unix系统管理员。那次来竞聘该岗位的共有8个人,其中两人是技术***的自由职业者。我认为系统管理员没必要把所有的配置方法熟记于心,需要某个软件的时候,只要你想把它玩转并且玩得更酷,多读些文章,你便会自然而然地熟悉它的各种用法与配置。于是,我让这些应聘者解决下面两个问题:

  1. 创建一个例行任务,它在每个偶数点(比如2点、12点)和3点执行;
  2. 通过/var/run/dmesg.boot文件打印处理器信息。

让我吃惊的是,8位应聘者中没有一个人能解决上述问题,其中两人竟对grep命令一无所知。

介于此,我们就好好说说grep。

首先,以下所有的操作都是基于grep 2.5.1-FreeBSD:

  1. # grep --version | grep grep
  2. grep (GNU grep) 2.5.1-FreeBSD

有必要先交待下grep版本,因为某些用法只限定于特定的版本:

  1. # man grep | grep -iB 2 freebsd

  2. -P, --perl-regexp

  3. Interpret PATTERN as a Perl regular expression. This option is

  4. not supported in FreeBSD.

好了,言归正传,我们经常会这样grep文件:

  1. root@nm3:/ # cat /var/run/dmesg.boot | grep CPU:
  2. CPU: Intel Core(TM)2 Quad CPU Q9550 @ 2.83GHz (2833.07-MHz K8-class CPU)

还可以这样做:

  1. root@nm3:/ # grep CPU: /var/run/dmesg.boot
  2. CPU: Intel Core(TM)2 Quad CPU Q9550 @ 2.83GHz (2833.07-MHz K8-class CPU)

这样也是可以的(虽然我很讨厌这种操作方式):

  1. root@nm3:/ # </var/run/dmesg.boot grep CPU:
  2. CPU: Intel Core(TM)2 Quad CPU Q9550 @ 2.83GHz (2833.07-MHz K8-class CPU)

你肯定会遇到这样的场景:统计文件中带有某些关键字的行出现的次数。grep+wc可以帮到你:

  1. root@nm3:/ # grep WARNING /var/run/dmesg.boot | wc -l
  2. 3

条条大路通罗马,下面是另一条路:

  1. root@nm3:/ # grep WARNING /var/run/dmesg.boot -c
  2. 3

下面我们新建一个测试用的文档:

  1. root@nm3:/ # grep ".*" test.txt
  2. one two three
  3. seven eight one eight three
  4. thirteen fourteen fifteen
  5. sixteen seventeen eighteen seven
  6. sixteen seventeen eighteen
  7. twenty seven
  8. one 504 one
  9. one 503 one
  10. one 504 one
  11. one 504 one
  12. #comment UP
  13. twentyseven
  14. #comment down
  15. twenty1
  16. twenty3
  17. twenty5
  18. twenty7

继续grep的搜索之旅。

-w选项指定要搜索的单词:

  1. root@nm3:/ # grep -w 'seven' test.txt
  2. seven eight one eight three
  3. sixteen seventeen eighteen seven
  4. twenty seven

如果想搜以特定字符开头(结尾)的单词,可以这样:

  1. root@nm3:/ # grep '<seven' test.txt
  2. seven eight one eight three
  3. sixteen seventeen eighteen seven
  4. sixteen seventeen eighteen
  5. twenty seven
  6. root@nm3:/ # grep 'seven>' test.txt
  7. seven eight one eight three
  8. sixteen seventeen eighteen seven
  9. twenty seven
  10. twentyseven

如果想搜以特定字符开头(结尾)的行,可以这样:

  1. root@nm3:/ # grep '^seven' test.txt
  2. seven eight one eight three
  3. root@nm3:/ # grep 'seven$' test.txt
  4. sixteen seventeen eighteen seven
  5. twenty seven
  6. twentyseven
  7. root@nm3:/ #

想要显示目标行的上下文吗?

  1. root@nm3:/ # grep -C 1 twentyseven test.txt
  2. #comment UP
  3. twentyseven
  4. #comment down

到底是显示上文还是下文?

  1. root@nm3:/ # grep -A 1 twentyseven test.txt
  2. twentyseven
  3. #comment down
  4. root@nm3:/ # grep -B 1 twentyseven test.txt
  5. #comment UP
  6. twentyseven

我们还可以这样玩grep:

  1. root@nm3:/ # grep "twenty[1-4]" test.txt
  2. twenty1
  3. twenty3

或者取非:

  1. root@nm3:/ # grep "twenty[^1-4]" test.txt
  2. twenty seven
  3. twentyseven
  4. twenty5
  5. twenty7

grep是个强大的指令,除上述列举的之外,它还支持许多限定符、通配符以及正则表达式。下面是一些例子:

  1. root@nm3:/ # cat /etc/resolv.conf
  2. #options edns0
  3. #nameserver 127.0.0.1
  4. nameserver 8.8.8.8
  5. nameserver 77.88.8.8
  6. nameserver 8.8.4.4

只获取IP地址相关的行:

  1. root@nm3:/ # grep -E "[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}" /etc/resolv.conf
  2. #nameserver 127.0.0.1
  3. nameserver 8.8.8.8
  4. nameserver 77.88.8.8
  5. nameserver 8.8.4.4

上面的方法可行,但下面这种方法更好:

  1. root@nm3:/ # grep -E 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf
  2. #nameserver 127.0.0.1
  3. nameserver 8.8.8.8
  4. nameserver 77.88.8.8
  5. nameserver 8.8.4.4

希望去掉注释行?

  1. root@nm3:/ # grep -E 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf | grep -v '#'
  2. nameserver 8.8.8.8
  3. nameserver 77.88.8.8
  4. nameserver 8.8.4.4

只要IP:

  1. root@nm3:/ # grep -oE 'b[0-9]{1,3}(.[0-9]{1,3}){3}b' /etc/resolv.conf | grep -v '#'
  2. 127.0.0.1
  3. 8.8.8.8
  4. 77.88.8.8
  5. 8.8.4.4

哎呀,被注释掉的127.0.0.1又回来了,这是指令执行顺序不当导致的,怎么破?

  1. root@nm3:/ # grep -v '#' /etc/resolv.conf | grep -oE 'b[0-9]{1,3}(.[0-9]{1,3}){3}b'
  2. 8.8.8.8
  3. 77.88.8.8
  4. 8.8.4.4

下面看下-v(反向查找)选项的使用。

假设要执行指令“ps –afx | grep ttyv ”:

  1. root@nm3:/ # ps -afx | grep ttyv
  2. 1269 v1 Is+ 0:00.00 /usr/libexec/getty Pc ttyv1
  3. 1270 v2 Is+ 0:00.00 /usr/libexec/getty Pc ttyv2
  4. 1271 v3 Is+ 0:00.00 /usr/libexec/getty Pc ttyv3
  5. 1272 v4 Is+ 0:00.00 /usr/libexec/getty Pc ttyv4
  6. 1273 v5 Is+ 0:00.00 /usr/libexec/getty Pc ttyv5
  7. 1274 v6 Is+ 0:00.00 /usr/libexec/getty Pc ttyv6
  8. 1275 v7 Is+ 0:00.00 /usr/libexec/getty Pc ttyv7
  9. 48798 2 S+ 0:00.00 grep ttyv

OK,但是我们不需要“48798 2 S+ 0:00.00 grep ttyv”一行,使用-v:

  1. root@nm3:/ # ps -afx | grep ttyv | grep -v grep
  2. 1269 v1 Is+ 0:00.00 /usr/libexec/getty Pc ttyv1
  3. 1270 v2 Is+ 0:00.00 /usr/libexec/getty Pc ttyv2
  4. 1271 v3 Is+ 0:00.00 /usr/libexec/getty Pc ttyv3
  5. 1272 v4 Is+ 0:00.00 /usr/libexec/getty Pc ttyv4
  6. 1273 v5 Is+ 0:00.00 /usr/libexec/getty Pc ttyv5
  7. 1274 v6 Is+ 0:00.00 /usr/libexec/getty Pc ttyv6
  8. 1275 v7 Is+ 0:00.00 /usr/libexec/getty Pc ttyv7

看着不爽?现在呢?

  1. root@nm3:/ # ps -afx | grep "[t]tyv"
  2. 1269 v1 Is+ 0:00.00 /usr/libexec/getty Pc ttyv1
  3. 1270 v2 Is+ 0:00.00 /usr/libexec/getty Pc ttyv2
  4. 1271 v3 Is+ 0:00.00 /usr/libexec/getty Pc ttyv3
  5. 1272 v4 Is+ 0:00.00 /usr/libexec/getty Pc ttyv4
  6. 1273 v5 Is+ 0:00.00 /usr/libexec/getty Pc ttyv5
  7. 1274 v6 Is+ 0:00.00 /usr/libexec/getty Pc ttyv6
  8. 1275 v7 Is+ 0:00.00 /usr/libexec/getty Pc ttyv7

别忘了| (或)符号:

  1. root@nm3:/ # vmstat -z | grep -E "(sock|ITEM)"
  2. ITEM SIZE LIMIT USED FREE REQ FAIL SLEEP
  3. socket: 696, 130295, 30, 65, 43764, 0, 0

殊途同归:

  1. root@nm3:/ # vmstat -z | grep "sock|ITEM"
  2. ITEM SIZE LIMIT USED FREE REQ FAIL SLEEP
  3. socket: 696, 130295, 30, 65, 43825, 0, 0

许多人都会在grep中用正则表达式,但你仍会忘了用POSIX字符集,即便它们也非常有用。

POSIX:

  1. [:alpha:] Any alphabetical character, regardless of case
  2. [:digit:] Any numerical character
  3. [:alnum:] Any alphabetical or numerical character
  4. [:blank:] Space or tab characters
  5. [:xdigit:] Hexadecimal characters; any number or A–F or a–f
  6. [:punct:] Any punctuation symbol
  7. [:print:] Any printable character (not control characters)
  8. [:space:] Any whitespace character
  9. [:graph:] Exclude whitespace characters
  10. [:upper:] Any uppercase letter
  11. [:lower:] Any lowercase letter
  12. [:cntrl:] Control characters

找有大写字母的行:

  1. root@nm3:/ # grep "[[:upper:]]" test.txt
  2. #comment UP

搜索结构不够醒目?高亮显示:

 

更多的grep小窍门。***个稍显专业,我已经15年没用过了。

选择包含six,seven或者eight的行,很简单:

  1. root@nm3:/ # grep -E "(six|seven|eight)" test.txt
  2. seven eight one eight three
  3. sixteen seventeen eighteen seven
  4. sixteen seventeen eighteen
  5. twenty seven
  6. twentyseven

那么现在只选择包含six,seven或者eight若干次的行。这种用法叫回溯引用:

  1. root@nm3:/ # grep -E "(six|seven|eight).*1" test.txt
  2. seven eight one eight three
  3. sixteen seventeen eighteen seven

第二个窍门,这个更有用一些。打印504前后有tab的行(如果PCRE能够支持这个特性就好了)。

POSIX字符集在此失效了:

  1. root@nm3:/ # grep "[[:blank:]]504[[:blank:]]" test.txt
  2. one 504 one
  3. one 504 one
  4. one 504 one

[CTRL+V][TAB]生效:

  1. root@nm3:/ # grep " 504 " test.txt
  2. one 504 one

我漏讲什么了吗?grep具备递归搜索文件/目录功能。如果我们想在源码目录中搜索允许Intel使用外部SFPs的代码,但是又没清楚完整地记着函数名allow_unsupported_stp和unsupported_allow_sfp。肿么办?这正是grep的菜:

  1. root@nm3:/ # grep -rni allow /usr/src/sys/dev/ | grep unsupp
  2. /usr/src/sys/dev/ixgbe/README:75:of unsupported modules by setting the static variable 'allow_unsupported_sfp'
  3. /usr/src/sys/dev/ixgbe/ixgbe.c:322:static int allow_unsupported_sfp = TRUE;
  4. /usr/src/sys/dev/ixgbe/ixgbe.c:323:TUNABLE_INT("hw.ixgbe.unsupported_sfp", &allow_unsupported_sfp);
  5. /usr/src/sys/dev/ixgbe/ixgbe.c:542: hw->allow_unsupported_sfpallow_unsupported_sfp = allow_unsupported_sfp;
  6. /usr/src/sys/dev/ixgbe/ixgbe_type.h:3249: bool allow_unsupported_sfp;
  7. /usr/src/sys/dev/ixgbe/ixgbe_phy.c:1228: if (hw->allow_unsupported_sfp == TRUE) {

希望你还没晕,因为这些grep用法只是grep的冰山一角呢!

***祝大家 Happy grepping!

原文链接:http://outofmemory.cn/wr/?u=http%3A%2F%2Fwww.techug.com%2F

责任编辑:牛小雨 来源: 程序师
相关推荐

2023-07-18 09:03:01

RocketMQ场景消息

2015-07-23 09:20:19

mmap

2022-04-07 11:27:15

数字孪生VR系统AI

2015-08-26 14:15:12

数据挖掘

2017-04-03 15:35:13

知识体系架构

2022-09-16 11:33:40

数据分析MVP

2019-06-05 15:20:00

MongoDBNoSQL数据库

2010-03-18 16:06:19

Linux命令

2010-03-18 15:19:27

Linux命令

2010-03-18 17:00:57

Linux命令

2010-03-18 16:13:58

Linux命令

2020-08-10 07:44:13

虚拟内存交换内存Linux

2017-04-14 10:11:37

闪存备份用例

2023-10-31 08:21:18

WebFlux基本用法JPA

2011-03-29 14:11:20

Cacti基础知识

2022-11-04 11:44:56

WebFluxCURDWeb

2021-12-20 14:56:07

LinuxTTY

2023-03-02 08:48:43

Linuxsubshell

2015-02-09 16:09:00

布线施工顺序

2010-06-21 15:49:59

Linux apt是什
点赞
收藏

51CTO技术栈公众号