流过滤大量由 stdin 中的行号指定的行

Cor*_*mer 2 unix bash awk stream large-files

我有一个包含数百万行的巨大xz压缩文本文件huge.txt.xz,该文件太大而无法保持未压缩(60GB)。

我想从那个巨大的文本文件中快速过滤/选择大量行(~1000s)到一个文件中filtered.txt。例如,可以在单独的文本文件中指定要选择的行号,select.txt格式如下:

10
14
...
1499
15858
Run Code Online (Sandbox Code Playgroud)

总的来说,我设想了一个如下的 shell 命令,其中“待确定”是我正在寻找的命令:

10
14
...
1499
15858
Run Code Online (Sandbox Code Playgroud)

我设法awk从一个密切相关的问题中找到了一个几乎可以完成工作的程序 - 唯一的问题是它需要一个文件名而不是从stdin读取。不幸的是,我不太了解awk脚本,也不知道awk以这种方式更改它以在这种情况下工作。

这就是现在有效的方法,缺点是有 60GB 的文件存在而不是流式传输:

xz -dcq huge.txt.xz | "TO BE DETERMINED" select.txt >filtered.txt
Run Code Online (Sandbox Code Playgroud)

灵感:https : //unix.stackexchange.com/questions/612680/remove-lines-with-specific-line-number-specified-in-a-file

mar*_*rkp 6

与 OP 目前的想法保持一致:

xz -dcq huge.txt.xz | awk '!firstfile_proceed { nums[$1]; next } (FNR in nums)' select.txt firstfile_proceed=1 -
Run Code Online (Sandbox Code Playgroud)

-(在该行的结尾)告诉awk从标准输入读取(在这种情况下,从输出xz这是管道的awk呼叫)。

执行此操作的另一种方法(替换上述所有代码):

awk '
FNR==NR { nums[$1]; next }             # process first file
FNR in nums                            # process subsequent file(s)
' select.txt <(xz -dcq huge.txt.xz)
Run Code Online (Sandbox Code Playgroud)

评论被删除并缩减为“单行”:

awk 'FNR==NR {nums[$1];next} FNR in nums' select.txt <(xz -dcq huge.txt.xz)
Run Code Online (Sandbox Code Playgroud)

添加一些逻辑来实现 Ed Morton 的评论(一旦 FNR > 最大值就退出处理select.txt):

awk '
# process first file

FNR==NR      { nums[$1]
               maxFNR= ($1>maxFNR ? $1 : maxFNR)
               next
             }

# process subsequent file(s):

FNR > maxFNR { exit }
FNR in nums
' select.txt <(xz -dcq huge.txt.xz)
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 请记住,我们正在谈论扫描数百万行输入......
  • FNR > maxFNR显然会为整体操作增加一些 cpu/处理时间(虽然时间少于FNR in nums
  • 如果操作通常需要从文件的最后 25% 中提取行,那么FNR > maxFNR可能没有什么好处(并且可能会减慢操作速度)
  • 如果操作例行地在文件的前 50% 中找到所有所需的行,那么FNR> maxFNRCPU/处理时间可能值得避免扫描整个输入流(再次xz,对整个文件的操作很可能最大的时间消费者)
  • 最终结果:附加NFR > maxFNR测试可能会加速/减慢整个过程,具体取决于在典型运行中需要处理多少输入流;OP 需要运行一些测试来查看整体运行时间是否存在(明显的)差异