只有从特定行 X(带有模式)到其他特定行 Y(带有模式)的猫

Nul*_*ptr 3 grep sed awk tail head

从“ cat line x 到 line y on a large file ”的一个小问题:

我有一个巨大的文件(2-3 GB)。我只想从具有“foo:”的行到具有“goo:”的行进行猫/打印。假设“foo:”和“goo:”在一个文件中只出现一次;"foo:" 继续 "goo:"。

到目前为止,这是我的方法:

  • 首先,找到带有“foo:”和“goo:”的行: grep -nr "foo:" bigfile
  • 退货123456: foo: hello world!654321: goo: good bye!
  • 一旦我知道这些开始和结束行号,以及差异(654321-123456=530865),我就可以做选择性猫:
  • tail -n+123456 bigfile | head -n 530865

我的问题是如何用表达式(例如,grep ...)有效地替换行号常量?

我可以编写一个简单的 Python 脚本,但只想使用组合命令来实现它。

mik*_*erv 9

sed -n '/foo/,/goo/p;/goo/q' <bigfile
Run Code Online (Sandbox Code Playgroud)

那只会打印那些行。如果你想要行号,你可以添加一个=.

sed -n '/foo/=;/goo/=;//q' <bigfile
Run Code Online (Sandbox Code Playgroud)

q很重要,因为它q在调用时适合输入 - 否则sed将继续读取 infile 直到结束。

如果您不想打印foo/goo行,您可以改为:

使用 GNU sed

sed -n '/foo/,/goo/!d;//!p;/goo/q
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA
Run Code Online (Sandbox Code Playgroud)

输出

line3
line4
line5
Run Code Online (Sandbox Code Playgroud)

并与任何其他:

sed -n '/foo/G;/\n/,/goo/!d;//q;/\n/!p 
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA    
Run Code Online (Sandbox Code Playgroud)

输出

line3
line4
line5
Run Code Online (Sandbox Code Playgroud)

但是,无论哪种方式,只要遇到搜索中的最后一行,它也会立即退出输入。


Hal*_*ost 5

如果您可以放弃当前在子 shell 中使用某些内容来获取行号并允许另一个实用程序打印文件的方法,那么这可以完全轻松地完成awk

如果你要打印的行之间 foo:goo:而不是线本身,那么你可以使用以下(从这里原本拾起):

awk '/goo:/ { exit }; flag; /foo:/ { flag = 1 }' bigFile
Run Code Online (Sandbox Code Playgroud)

上面的exits 当它看到结束标记 ( goo:) 时,print如果 sflag为真,并在到达开始标记 ( )时设置flag为真 ( 1,实际上foo:)。

但是,如果您希望在输出中包含标记行,则该命令实际上更简单,正如@jasonwryan 所提到的

awk '/foo:/,/goo:/' bigFile
Run Code Online (Sandbox Code Playgroud)

如果您一心只想获取行号,而不是使用相同的实用程序实际打印文件,那么您可以像这样获取开始和结束标记的行号:

awk '/foo:|goo:/ { print NR }' bigFile
Run Code Online (Sandbox Code Playgroud)

  • 或者,如果您还想要匹配项:`awk '/foo/,/goo/' bigfile` (4认同)