我有40个文件,每个2GB,存储在NFS架构上。每个文件包含两列:数字ID和文本字段。每个文件都已经过排序和压缩。
如何合并所有这些文件,以便对结果输出进行排序?
我知道sort -m -k 1
应该为未压缩文件做技巧,但我不知道如何直接使用压缩文件。
PS:我不想要将文件解压缩到磁盘,合并它们以及再次压缩的简单解决方案,因为我没有足够的磁盘空间。
答案 0 :(得分:16)
这是进程替换的用例。假设您有两个要排序的文件,sorta.gz
和sortb.gz
。您可以使用gunzip -c FILE.gz
shell运算符给出<(...)
的输出以对这两个文件进行排序:
sort -m -k1 <(gunzip -c sorta.gz) <(gunzip -c sortb.gz) >sorted
进程替换使用表示该命令输出的文件名替换命令,通常使用命名管道或/dev/fd/...
特殊文件实现。
对于40个文件,您需要动态创建包含许多进程替换的命令,并使用eval
执行它:
cmd="sort -m -k1 "
for input in file1.gz file2.gz file3.gz ...; do
cmd="$cmd <(gunzip -c '$input')"
done
eval "$cmd" >sorted # or eval "$cmd" | gzip -c > sorted.gz
答案 1 :(得分:2)
#!/bin/bash
FILES=file*.gz # list of your 40 gzip files
# (e.g. file1.gz ... file40.gz)
WORK1="merged.gz" # first temp file and the final file
WORK2="tempfile.gz" # second temp file
> "$WORK1" # create empty final file
> "$WORK2" # create empty temp file
gzip -qc "$WORK2" > "$WORK1" # compress content of empty second
# file to first temp file
for I in $FILES; do
echo current file: "$I"
sort -k 1 -m <(gunzip -c "$I") <(gunzip -c "$WORK1") | gzip -c > "$WORK2"
mv "$WORK2" "$WORK1"
done
使用bash globbing文件列表(文件* .gz)或40个文件名列表(用白色空格分隔)以最简单的方式填写$ FILES。 $ FILES中的文件保持不变。
最后,80 GB数据在$ WORK1中压缩。处理此脚本时,没有未压缩的数据写入磁盘。
答案 2 :(得分:1)
在单个管道中添加不同风格的多文件合并 - 它需要$OUT/uniques
中的所有(预先排序的)文件,对它们进行排序合并并压缩输出,因为它使用了lz4&#39;速度:
find $OUT/uniques -name '*.lz4' |
awk '{print "<( <" $0 " lz4cat )"}' |
tr "\n" " " |
(echo -n sort -m -k3b -k2 " "; cat -; echo) |
bash |
lz4 \
> $OUT/uniques-merged.tsv.lz4
答案 3 :(得分:-2)
确实有zgrep和其他常用实用程序可以使用压缩文件,但在这种情况下,您需要对未压缩数据进行排序/合并并压缩结果。