2011-06-13 188 views
5

我有些排序,目錄中的gzip文件。我如何將其中的一些文件合併到另一個經過排序的gzip文件中?現在我正在使用顯式的fifos。有沒有辦法在bash中完成它?我是一個bash noob,所以請原諒我缺乏風格。合併排序的文件與FIFO的

#!/bin/bash 
# Invocation ./merge [files ... ] 
# Turns an arbitrary set of sorted, gzipped files into a single sorted, gzipped file, 
# printed to stdout. Redirect this script's output! 
for f in [email protected] 
do 
    mkfifo $f.raw 
    gzcat $f > $f.raw & 
    # sort -C $f.raw 
done 
sort -mu *.raw | gzip -C# prints to stdout. 
rm -f *.raw 

我期待這個轉變成類似...

sort -mu <(gzcat $1) <(gzcat $2) <(gzcat $3) ... | gzip -9C# prints to stdout. 

...但不知道怎麼辦。我需要一個建立參數到字符串的循環嗎?這有什麼魔術捷徑嗎?也許map gzcat [email protected]

注:每個文件是超過10GB(100GB和解壓)的。我有一個2TB的驅動器,所以這不是一個真正的問題。另外,這個程序必須在O(n)中運行,否則它變得不可行。

+1

我在回答時看到你編輯了這個問題 - 是的,你需要一個循環來構建命令字符串,並且可以使用'eval'或'bash -c「$ cmd」'來執行它。 – 2011-06-13 05:30:27

回答

3

你可以使用bash結合eval和「進程替換」。假設基本的文件名不包含空格(假定您使用[email protected]代替"[email protected]"大概就是這樣),那麼這樣的:

cmd="sort -mu" 
for file in "[email protected]" 
do cmd="$cmd <(gzip -cd $file)" 
done 
eval $cmd | gzip -c9 > outputfile.gz 

您也可以在最後一行用bash -c "$cmd"代替eval $cmd 。如果文件名中有空格,則必須更加努力。這適用於名稱不包含單引號的情況:

cmd="sort -mu" 
for file in "[email protected]" 
do cmd="$cmd <(gzip -cd '$file')" 
done 
eval $cmd | gzip -c9 > outputfile.gz 

同樣在文件名中使用單引號,您必須更加努力地工作。

1

對於我來說,你的問題是有點不清楚,但如果我明白你的需要,試試這個:

gunzip -c file1 file2 .... | sort | gzip -9 > mergedFile.gz 

如果你想要做在1個DIR某一類型的所有文件,那麼你可以使用file*.type作爲gunzip的輸入列表,否則,根據我的示例,您需要明確列出每個文件。

-c選項表示「將輸出發送到標準輸出」,這是由管道,送到sort,這將其輸出發送到stdout,管道讀,和gzip格式,與它的標準輸出重定向到最終文件。該是最高的壓縮,它給你最小的文件(gzip的),但需要更長的時間。您可以給出一個介於-1和-9之間的明確數字來調整壓縮大小/時間,以便根據您的需要進行壓縮折衷。

我希望這會有所幫助。

+0

我真的想排序-mu使用,如果我們在一個去gunzip文件將無法正常工作。它從O(nlogn)變爲O(n)。 – 2011-06-13 04:50:56

+0

我通常會使用一個明確的'gzip -c -9',但我想這會起作用。 – 2011-06-13 05:03:24

+0

所以你有大文件,你正在尋找一種方式來通過預先排序小文件並在最後合併它們來並行化進程?你有多CPU,你可以分配給每個較小的排序過程?你想節省時間,或CPU,或?有很多人對S.O.的性能調整感興趣。您可能會添加標記以進行基準測試,測試和性能調優,以獲取有關如何解決此問題的更好建議。祝你好運。 – shellter 2011-06-13 05:03:58

1

與文件名單引號過,你必須更加努力才行。

這裏有一種方法可以在包含單引號的變量中得到eval'的文件名(或文件路徑)中的單引號。

(
esc="'\''" 
file="/Applications/iWork '09/Pages.app" 
file="${file//\'/${esc}}" 
#echo "'${file}'"; ls -bdl "'${file}'" 
evalstr="echo '${file}'; ls -bdl '${file}'" 
#set -xv 
eval "${evalstr}" 
)