9.12 查看文件中搜索内容的上下文信息

-A, -B, -C

在处理数据时,上下文至关重要。前面学过,grep可以输出包含搜索内容的实际行,但也可以让grep输出匹配内容之前和之后的若干行。在9.11节中,曾经用grep来搜索John Coltrane专辑。他最好的专辑是A Love Supreme,那么这个专辑之前的三个专辑又是什么呢?使用-B(或--before-context=#)选项,就可以得到答案。如下所示:

  1. $ ls -1 | grep -B 3 A_Love_Supreme
  2. 1963_Impressions
  3. 1963_John_Coltrane_&_Johnny_Hartman
  4. 1963_Live_At_Birdland
  5. 1964_A_Love_Supreme

如果要找出A Love Supreme之后的唱片,则应该使用-A(或--after-context=#)选项。如下所示:

  1. $ ls -1 | grep -A 3 'A_Love_Supreme'
  2. 1964_A_Love_Supreme
  3. 1964_Coltrane's_Sound
  4. 1964_Crescent
  5. 1965_Ascension

而要得到A Love Supreme专辑的完整历史背景,则可以试试-C(或--context=#)选项,它可以把该专辑之前和之后的内容都组合在一起。

  1. $ ls -1 | grep -C 2 'A_Love_Supreme'
  2. 1963_John_Coltrane_&_Johnny_Hartman
  3. 1963_Live_At_Birdland
  4. 1964_A_Love_Supreme
  5. 1964_Coltrane's_Sound
  6. 1964_Crescent

对于在一个文件或一组文件中有多个匹配结果的情况,这样的显示方式可能会有点让人困惑。例如,Coltrane发行过一些演唱会专辑(live album),如果你想看看这些专辑前后的其他专辑,将会得到更加复杂的结果。如下所示:

  1. $ ls -1 | grep -C 1 Live
  2. 1963_John_Coltrane_&_Johnny_Hartman
  3. 1963_Live_At_Birdland
  4. 1964_A_Love_Supreme
  5. --
  6. 1965_Last_Trane
  7. 1965_Live_in_Seattle
  8. 1965_Major_Works_of_John_Coltrane
  9. --
  10. 1965_Transition
  11. 1966_Live_at_the_Village_Vanguard_Again!
  12. 1966_Live_in_Japan
  13. 1967_Expression
  14. 1967_Olatunji_Concert_Last_Live_Recording
  15. 1967_Stellar_Regions

以上结果中,用两个连字符(--)将每组匹配结果分隔开。前两组结果很明显(标题中包含Live的专辑在中间,在它之前和之后各有另一个专辑),但最后一组看起来要复杂得多。在标题中包含Live的多个专辑彼此紧挨着列在中间,所以结果都堆在了一起。这样的结果看起来可能会有些怪异,但是如果你看一下每个Live实例,就会注意到相关专辑之前和之后的专辑实际上都是列好的。

如果结合-n选项,结果中的信息将更有用,该选项可以列出行号(因为这里使用的是ls -1,所以它是ls结果列表中的行号)。

  1. $ ls -1 | grep -n -C 1 Live
  2. 37-1963_John_Coltrane_&_Johnny_Hartman
  3. 38:1963_Live_At_Birdland
  4. 39-1964_A_Love_Supreme
  5. --
  6. 48-1965_Last_Trane
  7. 49:1965_Live_in_Seattle
  8. 50-1965_Major_Works_of_John_Coltrane
  9. --
  10. 52-1965_Transition
  11. 53:1966_Live_at_the_Village_Vanguard_Again!
  12. 54:1966_Live_in_Japan
  13. 55-1967_Expression
  14. 56:1967_Olatunji_Concert_Last_Live_Recording
  15. 57-1967_Stellar_Regions

现在通过行号数字后面的不同字符,-C选项可以为每一行提供更多的信息。冒号(:)表示该行是匹配行,而连字符(-)则表示该行是匹配行之前或之后的行。54行(1966_Live_in_Japan)具有双重作用。它在1966_Live_at_the_Village_Vanguard_Again!(这是一个匹配行)之后,因而应该用连字符;但54行本身也是一个匹配行,因而需要用冒号。因为匹配行更加重要,匹配符获胜,所以这一行最终使用了冒号。