2011-06-13 190 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}" 
)