2014-07-03 4 views
5

Ho 40 file da 2 GB ciascuno, archiviati in un'architettura NFS. Ogni file contiene due colonne: un ID numerico e un campo di testo. Ogni file è già ordinato e gzip.Unisci file gzip ordinati

Come posso unire tutti questi file in modo che anche l'output risultante sia ordinato?

So che sort -m -k 1 dovrebbe fare il trucco per i file non compressi, ma non so come farlo direttamente con quelli compressi.

PS: Non voglio la semplice soluzione di decomprimere i file su disco, unirli e comprimerli di nuovo, perché non ho abbastanza spazio su disco per quello.

+2

e 'possibile sviluppare un programma che aprirà tutti i file, decomprimere un blocco alla volta, unisci, ordina i dati, outp ut i risultati (compressi se lo si desidera) e anticipare ogni input secondo necessità, ma l'ambito di tale sforzo va oltre una semplice risposta qui. –

+0

@AndrewMedico Per la cronaca, questo non è vero - 'sort' è esattamente un tale programma, e' bash' può combinarlo con 'gunzip' abbastanza facilmente. Vedi le risposte per i dettagli. – user4815162342

risposta

11

Questo è un caso di utilizzo per la sostituzione di processo . Supponi di avere due file da ordinare, sorta.gz e sortb.gz. È possibile dare l'uscita di gunzip -c FILE.gz per ordinare per entrambi questi file utilizzando l'operatore <(...) shell:

sort -m -k1 <(gunzip -c sorta.gz) <(gunzip -c sortb.gz) >sorted 

sostituzione di processo sostituisce un comando con un nome di file che rappresenta l'uscita del comando, e viene tipicamente implementato con entrambi una named pipe o un file speciale /dev/fd/....

Per 40 file, si vuole creare il comando con che molte sostituzioni di processo dinamico, e utilizzare eval per eseguirlo:

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 
+0

Fantastico - Grazie! – mossaab

-1

È vero che esistono zgrep e altre utilità comuni che funzionano con i file compressi, ma in questo caso è necessario ordinare/unire i dati non compressi e comprimere il risultato.

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 

Fill $ file nel modo più semplice con l'elenco dei file con bash globbing (file * .gz) o con un elenco di nomi di file 40 (separati con spazi bianchi). I tuoi file in $ FILES rimangono invariati.

Infine, i dati da 80 GB sono compressi in $ WORK1. Durante l'elaborazione di questo script non vengono scritti dati non compressi su disco.

1

Aggiunta di un multi-file in modo diverso al gusto si fondono in un unico gasdotto - è prende tutti i file (pre-assortiti) a $OUT/uniques, ordinarli-fonde e comprime l'uscita, LZ4 viene utilizzato a causa della sua velocità:

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