2012-11-10 19 views
1

我在一個文件夾中有數以百萬計的小純文本文件。我想通過一些處理將它們合併成一個大文件。什麼是最快的方法呢?目前,我有以下代碼:如何高效地將大量文件合併到bash中的單個文件中?


#!/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中解決這個問題。謝謝。

+2

沒有「掃描當前目標」,該文件以追加模式打開。 – Mat

回答

5

您可以重定向循環,而不是輸出:

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

(我也消除了useless use of cat。)

+0

當處理「數以億計」的文件時,這將創建數以億計的Perl進程,這將花費很長時間。這比問題中的示例代碼好得多,因爲移除UUOC會減少創建的進程數量,但使用'xargs'或'find ... -exec ... +'的解決方案會做得更好。移動重定向不太可能產生重大影響。還要注意'$ FILES'將包含千兆字節的數據,這可能會導致交換導致的性能問題。 – pjh

4

什麼是你的 '合併' 的定義是什麼?你的Perl腳本是否需要文件名參數?你的文件名是否包含空格或其他尷尬的角色?

假設你的腳本不帶命令行參數,你可以做的一個:

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

或者,如果是一個命令行的文件太多,則:

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

或者,如果您的名稱中有足夠的空間並且具有足夠現代的空間(符合POSIX 2008):

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

如果您確實想要始終附加到目標文件,請將>替換爲>>。在這些示例中,cat正在用於連接多個文件,這是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腳本不能(處理命令行參數),那麼我會使用第三個命令與cat和pipe。但是這說明了爲什麼您應該設計程序(Perl腳本)以儘可能像標準Unix過濾器那樣工作;這意味着您可以更有效地將它們組合到命令管道中。

+0

'cat $(找到$ FOLDER -name「* .txt」)'太可怕了! –

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 
-1

命令線路開關:

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

-p假設您的腳本週圍有輸入循環。線被打印。 -e用於輸入腳本的一行 '{}'空腳本

相關問題