3.4《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——grepping(检索目标行命令)

grep是检查文件内容最强大的工具之一,这也许不能代表什么,但这不是重点。的确,grep常用作动词,比如‘你完全应该检索(grep)那个文件’.

grep最常用于在文件中搜索子字符串。例如,我们在第三章节中学到的在莎士比亚诗中搜索'rose'字符串。而使用grep,我们可以直接找到标记,如Listing 16中展示的那样:

Listing 16: 寻找出现在莎士比亚诗中的'rose'

$ grep rose sonnets.txt
The rose looks fair, but fairer we it deem
As the perfumed tincture of the roses.
Die to themselves. Sweet roses do not so;
Roses of shadow, since his rose is true?
Which, like a canker in the fragrant rose,
Nor praise the deep vermilion in the rose;
The roses fearfully on thorns did stand,
Save thou, my rose, in it thou art my all.
I have seen roses damask'd, red and white,
But no such roses see I in her cheeks;

使用Listing 16中的命令,看来我们得用WC来计数‘rose’个数了(3.3章中介绍过), 正如Listing 17中:

Listing 17:* 对grep的输出结果使用wc*

$ grep rose sonnets.txt | wc

10 82 419

在上面👆Listing 17中我们得知有10行包含'rose'(或'roses',因为'rose'是‘roses’的自字符串)。但是你可能在之前的插图12中看到莎士比亚的第一首诗就包含"Rose",以大写字母'R'开始,再看Listing 16,我们会发现事实上这行被忽略了。这是因为grep默认要区分大小写字母,'rose'不匹配"Rose".

正如你猜想那样,grep也有个选项可以改变大小区分匹配方式。要弄清楚是哪个选项有个方法是搜索grepman手册页:

  • 输入 man grep
  • 在输入 /case 然后回车
  • 阅读结果(插图19)

(正如1.3章节中简洁批注样,手册页使用与3.3章遇到的less命令相同的用户界面,所以我们可以通过/来搜索)

插图19: 在`man grep`的结果中搜索'case'的结果

运用以上学到的知识像Listing 18那样操作。比较Listing 18和Listing 17的结果,我们看到现在有12行匹配而不只是10行了,所以诗中总共有12 -10 = 2行包含'Rose'(但不是'rose')。

Listing 18: 不区分大小写的grep

$ grep -i rose sonnets.txt | wc
12 96 508

grep工具非常非常强大,特别是与所谓的正则表达式结合在一起时,但是学习grepgrep -i几乎是很厉害的了(包括用grep搜索寻找过程中的重要应用(Box 10)).在第四章中我们会发现第三和最后个grep会变得更加厉害。

Box 10 搜索命令过程

grep的众多用途之一是过滤找到众多运行Unix进程的匹配进程。(在似Unix系统中,如Linux和macOS, 用户和每个系统会各占进程,即定义好的容器中。)这对杀死流氓程序非常有用。(查找这些进程的好办法是运行‘stop’命令,它会显示消耗最多资源的进程。)

例如,在Ruby Rails的教程中里有一点,在进程列表中清除'spring'的程序非常重要。要清除的话,首先要找到这个进程,要查看系统中所有的进程用ps命令加上aux选项:
$ ps aux
图16, ps 是'process status'的简写。由于模糊不清,ps选项没有用短横线(所以它用ps aux 而不是 ps -aux)。(地球人怎么会懂?这正是本篇教程的目的,介绍这些知识。)

通过程序名过滤进程,你可以通过grep管道输出ps的结果:

$ ps aux | grep spring
ubuntu 12241 0.3 0.5 589960 178416 ? Ssl Sep20 1:46
spring app | sample_app | started 7 hours ago

结果中展示了一些进程的细节,但是最总要的是第一个数字,就是进程的id,或者pid(与kid发音押韵)。要清楚一个不想要的进程,我们使用kill命令终止Unix代码pid(正好是15)的进程:

$ kill -15 12241

这是我建议杀死单个进程的技术,比如流氓网页服务(通过ps aux | grep server查找pid), 但有很容易杀掉与特定进程名匹配的所有进程,比如杀死所有消耗系统资源的'spring'进程。在这种情况下,可以像下面这样使用'pkill'杀死所有带有名'spring'的进程:

$ pkill -15 -f spring

不是所有时候都能如预期表现,或冻结一个进程,有个好办法是,运行top或者ps aux查看什么在运行,通过grep与ps aux选出可疑进程,然后在执行kill -15 或者 pkill -15 -f 这样就会更清楚了。

练习

  1. 通过搜索man grep手册页中的'line number', 构建命令查找sonnets.txt中'rose'出现的行数。
  2. 你应该发现了最后出现'rose'(匹配的 'roses')在2203行。弄清楚运行less sonnets.txt时做噩梦直接跳到这行。备注: 再查阅Table 4中,1G可以到文件的顶部,即就是1行。类似地,17G就到 17行等。

3.通过piping grep的输出head,只打印出'sonnets.txt'中包含'rose'的第一行。备注:使用3.2.2章节中的第二个练习。
4.在Listing 18中,我们看到另外两个不区分大小写匹配'rose'。执行命名确认这两行都包含字符串"Rose"(而不是其他的,像'rOSe'). 备注: 使用匹配大小写的'grep'搜索"Rose".
5.在之前的练习中可能你已经发现了其实有3行匹配"Rose"而不是Listing 18中预期的2行。这是因为有一行即包含了"Rose"又包含了"rose", 因此在运行命令grep rosegrep -i rose时都出现了。写一条命令确认匹配“Rose”但不匹配"rose"的命令,预期是2。备注:pipe grep的结果和grep -v,然后将结果与wc管道输出。(-v是干嘛的? 阅读grep的手册页(Box 5)).

posted @ 2018-03-22 16:00  印前  阅读(353)  评论(0编辑  收藏  举报