2

我在一个文件夹中有数亿个小的纯文本文件。我想通过一些处理将它们合并到一个大文件中。最快的方法是什么?目前,我有以下代码:


#!/bin/bash
FOLDER="some-folder"
TARGET="target-file"
FILES=`find $FOLDER -name "*.txt"`
for f in $FILES
  do
    cat $f | ./some-processing-script.pl >> $TARGET
  done

虽然这适用于少量文件。实际用于处理大文件集时,目标文件大于25G左右后变得非常慢。我认为是因为cat ... >> $TARGET,在将新内容附加到目标末尾之前,它必须为每个新输入文件扫描整个当前目标文件。

我知道如何使用 java 或 python 来解决这个问题。我只是好奇我是否可以在 bash 中解决这个问题。谢谢。

4

5 回答 5

5

您可以改为重定向循环的输出:

for f in $FILES
  do
    ./some-processing-script.pl < $f
  done >> $TARGET

(我还消除了cat 的无用用法。)

于 2012-11-10T06:35:28.423 回答
4

你对“合并”的定义是什么?您的 Perl 脚本是否采用文件名参数?您的文件名是否曾经包含空格或其他尴尬的字符?

假设您的脚本不接受命令行参数,您可以执行以下操作之一:

cat $(find $FOLDER -name "*.txt") | ./some-processing-script.pl >$TARGET

或者,如果单个命令行的文件太多,则:

find $FOLDER -name "*.txt" -print | xargs cat | ./some-processing-script.pl > $TARGET

或者,如果您的名称中有空格并且足够现代find(符合 POSIX 2008):

find $FOLDER -name "*.txt" -exec cat {} + | ./some-processing-script.pl > $TARGET

如果您真的想始终附加到目标文件,则将 替换>>>. 在这些示例中,catis 用于连接多个文件,这是cat. UUOC(无用的使用cat)奖与使用cat在 I/O 重定向将完成工作时处理单个文件一起使用。

如果您负责 Perl 脚本,则应将其修改为“标准过滤器”,即读取命令行上指定的文件的程序,如果没有指定文件,则读取标准输入。然后,您可以消除cat

 ./some-processing-script.pl $(find $FOLDER -name "*.txt") >$TARGET

find $FOLDER -name "*.txt" -print | xargs ./some-processing-script.pl > $TARGET

find $FOLDER -name "*.txt" -exec ./some-processing-script.pl {} + > $TARGET

在这些选项中,最后一个是我将使用的选项,假设 Perl 脚本接受或可以修改为接受命令行上的文件名。如果 Perl 脚本不能(被要求)处理命令行参数,那么我将使用带有catand 管道的第三个命令。但这说明了为什么您应该尽可能设计程序(Perl 脚本)以使其表现得像标准的 Unix 过滤器。这意味着您可以更有效地将它们组合到命令管道中。

于 2012-11-10T06:36:38.637 回答
0

如果您可以修改perl脚本,我建议使用:

shopt -s globstar # enable bash4 recursion with **
./some-processing-script.pl **/*.txt > big_file.txt

perl脚本:

while (<>) {
    # processing the content
    print;
}

你也可以这样做:

find $FOLDER -name "*.txt" -exec cat {} + |
    ./some-processing-script.pl > big_file.txt
于 2012-11-10T20:56:50.160 回答
0

我在一个目录中的 23k 个文件上尝试了这 bash 行代码,我认为速度是可以接受的。

for f in path/*.txt; do cat "${f}" >> merged.txt; done

参考:https ://www.unix.com/shell-programming-and-scripting/148505-concatenation-large-number-files.html

于 2020-10-28T20:52:51.140 回答
-1

使用命令行开关:

perl -pe '{}' abc_file_qualifiier_*.csv > merged_file.csv

-p假设您的脚本有一个输入循环。打印行。 -e用于输入一行脚本 '{}'一个空脚本

于 2016-04-05T23:09:59.423 回答