【问题标题】:grep to multiple files in order to scan an input file oncegrep 到多个文件以便扫描输入文件一次
【发布时间】:2016-10-04 07:12:38
【问题描述】:

我有一百个 CSV 文件,每个文件有 20 万行,压缩为 gzip。
所有具有相同结构的文件。第 15 列和第 18 列包含 companyID 和操作。
两列在一行中都是唯一的。 我想为每个 copanyID.action 创建一个文件。 现在我运行这个命令:

zcat * | grep 'companyID.*action' | gzip > companyID.action.gz

为了避免磁盘 IO,我对所有内容进行管道传输。

问题是我们有数百家公司和大约 20 个行动。 对每个 companyID X 操作运行此命令每次都会扫描整个数据。

我正在寻找一种解决方案,即扫描输入文件一次并在正确的文件中写入一行,如果文件不存在,则创建一个。

我更喜欢 bash 或 Golang 代码,但速度很重要,因此每个解决方案都值得一试

【问题讨论】:

  • zcating 所有文件并通过相关列将输出传送到sort 怎么样?
  • @choroba sort 不会将输出拆分为不同的文件。
  • @Barmar:这将是下一步,但一旦对数据进行排序,这将是微不足道的。
  • @choroba 不是同一个问题吗?为什么将同一个文件的所有行放在一起会更容易?
  • @Barmar:如果整个结构太大而无法保存在内存中,它仍然可以工作。

标签: bash csv grep


【解决方案1】:

请使用awk

scat * | awk '{ print | "gzip > " $15 "." $18 ".gzip" }'

【讨论】:

  • shopt -s nullglobscat * 之前有用。
  • 如果你有很多模式,Awk 会用完文件句柄。您可以在每次写入后close,但这会导致显着的性能损失。在这种情况下,可能会切换到更强大的语言;这在 Python 或 Perl(或者,我猜是 Ruby)中应该很容易和舒适。
  • @tripleee 如果您在每次写入后关闭,gzip 将在您每次写入时创建一个新文件。
  • 是的,您当然必须更改为附加重定向>>
  • @tripleee 这就是我最初写答案的方式,但我改为使用管道
【解决方案2】:

应该这样做:

zcat * |
awk -F, '{cmd="gzip >> \""$15"."$18".zip\""} cmd!=prev{close(prev)} {print | cmd; prev=cmd}'

使用 GNU awk,您不需要 cmd!=prev{close(prev)} 部分,如果需要:

zcat * |
sort -t, -k15,15 -k18,18 |
awk -F, '{cmd="gzip > \""$15"."$18".zip\""} cmd!=prev{close(prev)} {print | cmd; prev=cmd}'

它可能会运行得更快,因为它只会在 awk 命令中打开/关闭每个输出管道一次,这取决于sort 需要多长时间。

【讨论】:

    【解决方案3】:

    我不知道scat 做了什么。我改用zcat。我按相关列对所有文件的所有行进行了排序,然后在 Perl 中处理输出,当相关列中的值发生变化时更改输出文件:

    zcat *.csv.gz \
    | sort -t, -k15,15 -k18,18 \
    | perl -laF, -ne '
        if ($company ne $F[14] || $action ne $F[17]) {
            ($company, $action) = @F[14, 17];
            open FH, ">", "$company.$action.csv"
        }
        print FH $_'
    gzip *.*.csv
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 2022-11-02
      相关资源
      最近更新 更多