9.12 查看文件中搜索内容的上下文信息
-A, -B, -C
在处理数据时,上下文至关重要。前面学过,grep
可以输出包含搜索内容的实际行,但也可以让grep
输出匹配内容之前和之后的若干行。在9.11节中,曾经用grep
来搜索John Coltrane专辑。他最好的专辑是A Love Supreme,那么这个专辑之前的三个专辑又是什么呢?使用-B
(或--before-context=#
)选项,就可以得到答案。如下所示:
$ ls -1 | grep -B 3 A_Love_Supreme
1963_Impressions
1963_John_Coltrane_&_Johnny_Hartman
1963_Live_At_Birdland
1964_A_Love_Supreme
如果要找出A Love Supreme之后的唱片,则应该使用-A
(或--after-context=#
)选项。如下所示:
$ ls -1 | grep -A 3 'A_Love_Supreme'
1964_A_Love_Supreme
1964_Coltrane's_Sound
1964_Crescent
1965_Ascension
而要得到A Love Supreme专辑的完整历史背景,则可以试试-C
(或--context=#
)选项,它可以把该专辑之前和之后的内容都组合在一起。
$ ls -1 | grep -C 2 'A_Love_Supreme'
1963_John_Coltrane_&_Johnny_Hartman
1963_Live_At_Birdland
1964_A_Love_Supreme
1964_Coltrane's_Sound
1964_Crescent
对于在一个文件或一组文件中有多个匹配结果的情况,这样的显示方式可能会有点让人困惑。例如,Coltrane发行过一些演唱会专辑(live album),如果你想看看这些专辑前后的其他专辑,将会得到更加复杂的结果。如下所示:
$ ls -1 | grep -C 1 Live
1963_John_Coltrane_&_Johnny_Hartman
1963_Live_At_Birdland
1964_A_Love_Supreme
--
1965_Last_Trane
1965_Live_in_Seattle
1965_Major_Works_of_John_Coltrane
--
1965_Transition
1966_Live_at_the_Village_Vanguard_Again!
1966_Live_in_Japan
1967_Expression
1967_Olatunji_Concert_Last_Live_Recording
1967_Stellar_Regions
以上结果中,用两个连字符(--
)将每组匹配结果分隔开。前两组结果很明显(标题中包含Live的专辑在中间,在它之前和之后各有另一个专辑),但最后一组看起来要复杂得多。在标题中包含Live的多个专辑彼此紧挨着列在中间,所以结果都堆在了一起。这样的结果看起来可能会有些怪异,但是如果你看一下每个Live实例,就会注意到相关专辑之前和之后的专辑实际上都是列好的。
如果结合-n
选项,结果中的信息将更有用,该选项可以列出行号(因为这里使用的是ls -1
,所以它是ls
结果列表中的行号)。
$ ls -1 | grep -n -C 1 Live
37-1963_John_Coltrane_&_Johnny_Hartman
38:1963_Live_At_Birdland
39-1964_A_Love_Supreme
--
48-1965_Last_Trane
49:1965_Live_in_Seattle
50-1965_Major_Works_of_John_Coltrane
--
52-1965_Transition
53:1966_Live_at_the_Village_Vanguard_Again!
54:1966_Live_in_Japan
55-1967_Expression
56:1967_Olatunji_Concert_Last_Live_Recording
57-1967_Stellar_Regions
现在通过行号数字后面的不同字符,-C
选项可以为每一行提供更多的信息。冒号(:
)表示该行是匹配行,而连字符(-
)则表示该行是匹配行之前或之后的行。54行(1966_Live_in_Japan
)具有双重作用。它在1966_Live_at_the_Village_Vanguard_Again!
(这是一个匹配行)之后,因而应该用连字符;但54行本身也是一个匹配行,因而需要用冒号。因为匹配行更加重要,匹配符获胜,所以这一行最终使用了冒号。