从结束到开始 Awking 文件的更快方法?

Faster way of Awking a file from End to Beginning?

我想从文件底部开始获取结果,然后一直到开头。我尝试使用 tac 并将其通过管道传输到我的 awk 命令中,但它非常慢(2GB 文件需要 15 秒)。与正常搜索相比(同一文件搜索 3 秒)。我还将 awk 命令传送到 tail -n +1 | head -n 50 以在 50 个结果后停止。

有没有更快的方法 tac 一个文件?或者至少从下往上开始搜索?

大局是创建一个 python 脚本,该脚本接受参数(开始日期、结束日期、搜索词)并使用这些参数来搜索按日期组织的日志文件。一次返回 50 个结果。

我需要从头到尾阅读,以防用户想要按降序(从最新日期到最旧日期)搜索。

用于升序结果的示例命令(“最旧到最新”): (我正在使用查找,因为是用户指定的参数,它可能会引用所有文件 (*.txt))

find '/home/logs/' -type f -name 'log_file.txt' -exec cat {} \+ 2>&1| LANC=C fgrep 'Potato' | LC_ALL=C IGNORECASE=1 awk -v start="2018-03-04T03:45:00" -v stop="2018-03-05T16:24:59" 'BEGIN{IGNORECASE=1;} {line=[=15=]; xz=" "; for(i=4;i<=NF;i++){xz=xz" "$i};} (>=start&&<=stop) && (tolower(xz) ~ /Potato/) {print line}' | tail -n +1 | head -n 50

tail -n +1 | head -n 50 是 return 前 50 场比赛。

此命令大约需要 3-4 秒才能找到结果,但是如果我在 tac 中进行 sub,则需要将近 20 秒。

好吧,如果你有记忆,散列记录并在 END 部分向后处理:

$ for i in {a..e} ; do echo $i ; done |   
  awk '{ a[NR]=[=10=] }       # hash to a, NR as key
  END {                   # in the end
      for(i=NR;i>=1;i--)  # process a in descending order
          c++             # process
      print c
}'
5

更新:我在上面测试了一个 1 GB 的文件(36 M 记录)。它在 1 分钟内进行了散列和计数,并占用了大约 4.5 GB 的内存。

一切都在一定程度上取决于您拥有的 awk 代码,但我想到的一些解决方案是:

  • 如果你打印每一行:

    tac <file> | awk '(NR > 50){exit}{do-your-stuff}'
    
  • 如果只打印几行 awk

    tac <file> | awk '(c > 50){exit} 
                      { do-part-of stuff;
                        print foobar; c++;
                        do-remaining part}'
    

两种解决方案都在前 50 行打印后终止 awk。这样您就不必处理整个 2GB 的文件。 50 行打印后的终止模仿 tail -n +1 | head -n 50

打开文件的速度大大加快,并在文件结束前搜索到一定数量。 Perl 在这里很方便:

perl -Mautodie -se '
    $size = -s $file;
    $blocksize = 64000;
    open $fh, "<", $file;
    seek $fh, $size - $blocksize, 0;
    read $fh, $data, $blocksize;
    @lines = split "\n", $data;
    # last 50 lines
    print join "\n", reverse @lines[-51..-1];
' -- -file="filename"

我们可以在其中加入一个循环,这样在它读取最后一个块之后,它可以寻找到减去 2 个块的末尾并读取一个块,等等。

但是如果你想从下到上处理整个巨大的文件,你将不得不期待它需要时间。