【问题标题】:Split a text file into multiple files based on filename given on each line根据每行给出的文件名将文本文件拆分为多个文件
【发布时间】:2022-10-24 21:06:05
【问题描述】:

我有一个大 (>10GB) 文件,它是一个 InfluxDB 线路协议导出。线路协议格式大致是

measurement,tag1=value1,tag2=value2,... value=XXX timestamp

例如

deconz.0.Sensors.10.pressure value=998 1622621407241000000
deconz.0.Sensors.10.pressure value=999 1622621970836000000
deconz.0.Sensors.10.pressure value=999 1622624177180000000
deconz.0.Sensors.10.pressure value=999 1622625419255000000
deconz.0.Sensors.10.pressure value=998 1622625975843000000
deconz.0.Sensors.11.battery value=85 1622621407241000000
deconz.0.Sensors.11.battery value=88 1622623616070000000
deconz.0.Sensors.11.battery value=88 1622660536826000000
deconz.0.Sensors.11.battery value=85 1622663594301000000
deconz.0.Sensors.11.battery value=88 1622666692089000000
deconz.0.Sensors.11.temperature value=21.44 1622621407241000000
deconz.0.Sensors.11.temperature value=21.61 1622646781032000000
deconz.0.Sensors.11.temperature value=21.64 1622650221200000000
deconz.0.Sensors.12.humidity value=55.54 1622621407242000000
deconz.0.Sensors.12.humidity value=55.7 1622633302339000000
deconz.0.Sensors.12.humidity value=55.73 1622636722283000000
deconz.0.Sensors.12.humidity value=55.89 1622640061715000000
deconz.0.Sensors.12.humidity value=55.96 1622643481822000000
deconz.0.Sensors.13.battery value=85 1622621407242000000
deconz.0.Sensors.13.battery value=85 1622908043752000000
deconz.0.Sensors.13.temperature value=24.01 1622621407242000000
deconz.0.Sensors.13.temperature value=24.13 1622626969228000000
deconz.0.Sensors.13.temperature value=24.21 1622630216027000000
deconz.0.Sensors.13.temperature value=24.33 1622630974954000000
deconz.0.Sensors.14.humidity value=47.72 1622632937200000000
deconz.0.Sensors.14.humidity value=47.8 1622633311833000000
deconz.0.Sensors.14.humidity value=46.7 1622636659393000000
deconz.0.Sensors.15.pressure value=1002 1622673441206000000
deconz.0.Sensors.15.pressure value=1002 1622685777307000000
deconz.0.Sensors.15.pressure value=1003 1622686242842000000
deconz.0.Sensors.16.temperature value=23.47 1622654455194000000
deconz.0.Sensors.16.temperature value=23.55 1622655939005000000
deconz.0.Sensors.16.temperature value=23.57 1622655959670000000
energymeter_total,uuid=c4695262-624c-11ea-b2f7-374e5ccddc43 value=30436.6 1622594844107000000
energymeter_total,uuid=c4695262-624c-11ea-b2f7-374e5ccddc43 value=30436.6 1622594908800000000
energymeter_total,uuid=c4695262-624c-11ea-b2f7-374e5ccddc43 value=30436.6 1622594973493000000
energymeter_total,uuid=c4695262-624c-11ea-b2f7-374e5ccddc43 value=30436.6 1622595158917000000
energymeter_total,manual=true value=26984.9 1592641140000000000

我想通过测量来分割这个文件,即。直到第一个逗号或空格,使用测量名称作为目标文件名。

这可以完成工作(逗号作为分隔符除外)但速度非常慢(在带有 SSD 存储的 Intel i5 上运行 8 小时):

cat ../influx_export | while read FILE VAL TS ; do echo "$FILE $VAL $TS" >> "$FILE" ; done

我确信有一个至少快 10 倍的脚本解决方案(无编译代码)。但是,源文件太大而无法完全放入 RAM。

有没有使用 awk、perl、sed、ruby 等更有效的方法?

【问题讨论】:

  • 到目前为止,您所写的内容可能意味着一些不同的事情。如果您 edit 您的问题包括 minimal reproducible example 简洁、可测试的样本输入和预期输出,那么我们可以为您提供帮助。
  • 输入文件是否已经按measurement 排序?如果没有,您是否大致了解我们必须处理多少个独特的measurements(又名文件名)?多行是否可以具有相同的measurement,如果是,是否所有具有相同measurement 的行都分组在一起?
  • 请使用更多示例数据更新问题(例如,5-10 行,3-4 个不同的measurements;带有多个标签/值对的几行);还使用预期结果更新问题(即,应生成的所有文件的名称和内容 - 对应于示例输入)
  • @markp-fuso,我希望单行就足够了。但我会再追加一些。感谢您的链接。该文件未排序(实际上,它是按时间戳排序的,但我不想依赖它)并且有大约 300 个独特的测量值。
  • 哦,哇,还有@ed-morton - 感谢您的冗长解释。使用 awk 我的 Haswell i5 能够在大约 5 分钟内完成任务。即使没有更多的调整。

标签: bash performance influx-line-protocol


【解决方案1】:

bash 对文件的迭代速度非常慢(因为 read 一次只读取一个字符,以确保它不会在换行符之后消耗任何可能供后续命令读取的内容)。

请改用awk

awk -F'[, ]' '{
   print $0 >> $1
}' ../influx_export

如果$1 有许多唯一值,您可能会遇到“打开的文件过多”错误。在这种情况下,一个简单(如果效率低下)的解决方案是在写入每个文件后立即显式关闭它。即使awk 需要为每一行打开一个文件,这仍然应该比使用纯bash 更快。

awk -F'[, ]' '{
   print $0 >> $1; close($1)
}' ../influx_export

【讨论】:

  • >> 在该上下文中是 shell 语法,而不是 awk 语法。您还缺少 ',不需要 $0,并且可能会从大多数 awk 中收到“打开的文件过多”错误,具体取决于生成的唯一输出文件的数量。 ( |,) = [ ,]
  • 但除此之外,罗马人为你做了什么...... :)
  • 我是苏格兰人,他们没能征服苏格兰,所以他们所做的一切都是为了我们在他们征服英格兰后建造哈德良长城试图阻止我们攻击他们:-)。
  • 我不清楚的一件事:awk 保证保持文件打开,除非明确关闭,对吧?所以>>>之间的唯一区别是>在文件第一次打开时会被截断;无论哪种方式,文本都可以积累在打开的文件中多次看到$1 的相同值,对吗?
  • 正确的。 awk '{print >> "file"}' 等价于 shell while IFS= read -r line; do echo "$line"; done >> file 当你几乎总是真正想要解决这样的问题时 awk '{print > "file"}' 相当于 shell while IFS= read -r line; do echo "$line"; done > file 所以,除此之外,你不必记住手动删除如果您运行该工具两次,则运行之间的输出文件。
【解决方案2】:

不要使用 shell 循环来操作文本,请参阅 why-is-using-a-shell-loop-to-process-text-considered-bad-practice

如果不完全正确,使用DSU 方法可能会接近您想要的:

awk -F'[, ]' '{print $1, NR, $(NF-1), $NF}' file |
sort -k1,1 -k2,2n |
awk '
    $1 != out {
        close(out)
        out = $1
    }
    { print $3, $4 > out }
'

但它显然未经测试,因为您没有提供我们可以测试的样本输入和预期输出。

awk 命令每次只处理 1 行,因此几乎不使用内存,sort 命令旨在通过使用请求分页等来处理大文件,因此它不需要将整个输入放入 RAM所以上面应该没有问题有效地处理您的输入文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-13
    • 1970-01-01
    • 2018-09-13
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多