linux - 基于循环模式和行数的日志拆分

标签 linux bash awk

我有一个系统正在生成非常大的文本日志(每个日志超过 1GB)。我输入它们的实用程序要求每个文件小于 500MB。我不能简单地使用 split 命令,因为这会冒将日志条目分成两半的风险,这会导致它们被馈送到的实用程序出错。

我对 split、csplit 和 awk 做了一些研究。到目前为止,我最幸运的是:

awk '/REG_EX/{if(NR%X >= (X-Y) || NR%2000 <= Y)x="split"++i;}{print > x;}' logFile.txt

在上面的示例中,X 表示我希望每个拆分文件包含的行数。实际上,这最终约为 1000 万。 Y 代表“加号或减号”。因此,如果我想要“1000 万正负 50”,Y 允许。

我实际使用的正则表达式并不重要,因为那部分有效。目标是将文件每隔 X 行拆分一次,但前提是它出现了 REG_EX。这就是 if() 子句出现的地方。我试图有一些正负 Y 线的“回旋余地”,因为不能保证 REG_EX 恰好存在于 NR%X 处。我的问题是,如果我将 Y 设置得太小,那么我最终得到的文件的行数是我的目标行数的两倍或三倍。如果我将 Y 设置得太大,那么我最终会得到一些包含 1 到 X 行之间任意位置的文件(REG_EX 可能会立即连续出现几次)。

如果没有编写自己的程序使用行计数器逐行遍历文件,我该如何优雅地解决这个问题?我有一个同事创建的脚本,但它很容易需要一个多小时才能完成。对于 X 值为 1000 万的 1.5GB 文件,我的 awk 命令在不到 60 秒的时间内完成,但这不是 100% 的解决方案。

== 编辑 ==

已找到解决方案。感谢所有花时间阅读我的问题、理解它并提供建议解决方案的人。他们中的大多数人都非常有帮助,但我标记为解决方案的那个提供了最大的帮助。我的问题是我的模块化数学是分界点。我需要一种方法来跟踪行并在每次拆分文件时重置计数器。作为 awk 的新手,我不确定如何利用 BEGIN{ ... }特征。请允许我总结问题集,然后列出解决问题的命令。

问题:
-- 系统产生文本日志 > 1.5GB
-- 日志输入的系统需要日志 <= 500MB。
-- 每个日志条目都以标准化行开始
-- 使用 split 命令有一个新文件开始时没有标准行的风险

要求:
-- 在第 X 行分割文件,但是
-- IFF 第 X 行是标准日志条目格式

注意:
-- 日志条目的长度各不相同,有些完全是空的

解决方案:

    awk 'BEGIN {min_line=10000000; curr_line=1; new_file="split1"; suff=1;} \
    /REG_EX/ \
    {if(curr_line >= min_line){new_file="split"++suff; curr_line=1;}} \
    {++curr_line; print > new_file;}' logFile.txt

命令可以在一行中输入;为了便于阅读,我在这里分解了它。一千万行的数据量在 450MB 到 500MB 之间。我意识到,考虑到标准日志条目行出现的频率,我不需要设置上限,只要我选择了一个有余地的下限。每次匹配 REG_EX 时,它都会检查当前行数是否大于我的限制,如果是,则启动一个新文件并重置我的计数器。

再次感谢大家。我希望遇到此问题或类似问题的其他任何人都觉得这很有用。

最佳答案

如果您想根据精确的 n 次模式出现次数创建拆分文件,您可以这样做:

awk '/^MYREGEX/ {++i; if(i%3==1){++j}} {print > "splitfilename"j}' logfile.log

地点:

  • ^MYREGEX 是您想要的模式。
  • 3 是模式的计数 您希望在每个文件中出现的次数。
  • splitfilename 是前缀 要创建的文件名。
  • logfile.log 是您的输入日志文件。
  • i 是一个计数器,每次出现该模式时都会递增。
  • j 是一个计数器,每出现第 n 次模式就会递增。

例子:

$ cat test.log
MY
123
ksdjfkdjk
MY
234
23
MY
345
MY
MY
456
MY
MY
xyz
xyz
MY
something

$ awk '/^MY/ {++i; if(i%3==1){++j}} {print > "file"j}' test.log

$ ls
file1  file2  file3  test.log

$ head file*
==> file1 <==
MY
123
ksdjfkdjk
MY
234
23
MY
345

==> file2 <==
MY
MY
456
MY

==> file3 <==
MY
xyz
xyz
MY
something

关于linux - 基于循环模式和行数的日志拆分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49309985/

相关文章:

linux - 使用 awk 从 grep 匹配中提取文本并并排放置

c - 从用户级别禁用键盘设备

c++ - 如何连接 wxWidgets、GTK2 小部件和 X11 窗口?

bash - 从基于 alpine 的 docker 运行 bash 脚本

php - 剩下的SSH进程/作业?

linux - 逐行读取模式之间的内容,然后以限定格式打印

c - 从 TCP 套接字读取错误数据

linux - 如何在 RHEL Linux 服务器上安装 Cargo?

Linux - 将文本文件的每一行与传递给函数的参数连接起来

linux - 如何使用 Awk 显示列中的文件名?