只从特定 X 行(带图案)到其他特定 Y 线(带图案)的猫

只从特定 X 行(带图案)到其他特定 Y 线(带图案)的猫

来自“的一个小扩展问题cat 第 x 行到大文件中的第 y 行”:

我有一个巨大的文件(2-3 GB)。我只想从具有“foo:”的行到具有“goo:”的行进行cat/打印。假设“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 脚本,但希望仅使用组合命令来实现它。

答案1

sed -n '/foo/,/goo/p;/goo/q' <bigfile

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

sed -n '/foo/=;/goo/=;//q' <bigfile

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

输出

line3
line4
line5

以及任何其他:

sed -n '/foo/G;/\n/,/goo/!d;//q;/\n/!p 
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA    

输出

line3
line4
line5

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

答案2

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

如果你想打印这些行之间 foo:goo:不是行本身,那么您可以使用以下(最初是从这里拾取的):

awk '/goo:/ { exit }; flag; /foo:/ { flag = 1 }' bigFile

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

但是,如果您希望在输出中包含令牌行,则该命令实际上更简单,如下所示@jasonwryan 提到:

awk '/foo:/,/goo:/' bigFile

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

awk '/foo:|goo:/ { print NR }' bigFile

答案3

替代方案sed一:

sed '/foo/,$!d;/goo/q'

答案4

要将常量替换为表达式,您可以使用命令替换

要将命令的输出替换为表达式,请使用$(command)

在这种情况下,适当的命令行是:

tail -n+$(grep -nr "foo:" bigfile | cut -d':' -f1) bigfile | \
head -n$(($(grep -nr "goo:" bigfile | cut -d':' -f1)-$(grep -nr "foo:" bigfile | cut -d':' -f1)+1))

这将打印从包含 的行foo:到包含 的行goo:(包含)的所有行。

相关内容