2011-06-13 13 views
5

Dizinde bazı sıralanmış, gziplenmiş dosyalar var. Bazılarını bir başka sıralanmış, gzipli dosyaya nasıl eklerim? Şu anda açık fifos kullanıyorum. Bash'ta bunu yapmanın bir yolu var mı? Ben biraz bash noob'um, bu yüzden lütfen benim tarzım eksikliğimi affedin.Sıralanan dosyaları fifos ile birleştirmek

#!/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 

Ben bir şey gibi dönüştürmek amacıyla arıyorum ...

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

... ama nasıl olduğunu bilmiyorum. Parametreleri dizeye oluşturmak için bir döngüye ihtiyacım var mı? Bunun için bir çeşit sihirli kısayol var mı? Belki map gzcat [email protected]?

NOT: Her bir dosya 10 GB'yi (ve 100 GB'lık açılmamış) aşıyor. 2TB sürücüm var, bu gerçekten sorun değil. Ayrıca, bu program O (n) 'de çalışması GEREKTİRİR veya uygun olmayan hale gelir. Benim için

+1

ben yanıtlayan iken soruyu düzenlenmiş bkz . –

cevap

3

eval ve 'process substitution' ile Bash'i birleştirebilirsiniz.

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

Ayrıca son satırında bash -c "$cmd" yerine eval $cmd kullanabilirsiniz: temel dosya isimleri varsayarsak sonra bir şey gibi (yerine "[email protected]" ait [email protected] muhtemelen durumda kullanmak göz önüne alındığında,) boşluk içermeyen . Dosya adlarında boşluk varsa, biraz daha sıkı çalışmanız gerekir. Eğer zor çok çalışmak zorunda, çok

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

dosya adlarında tek tırnak ile: isimler tek tırnak içermiyorsa, bu çalışır.

1

, sorunuz biraz belirsizdir, ama senin ihtiyacını anlamak, bu deneyin: Eğer 1 dir belli türdeki tüm dosyaları yapmak istiyorsanız o zaman kullanabilirsiniz,

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

Aksi halde, file*.type gunzip'in girdi listesi olarak, örneğime göre, her dosyayı açık bir şekilde listelemeniz gerekir. o stdout'u nihai dosyasına yönlendirilir ediliyor ile

-c seçenek, Stdout'a, boruya çıkışını gönderir sort gönderilen boru, tarafından okunan, 'Stdout'a çıktı göndermek' belirtir ve gzip içine . , en küçük dosya olan (gzip için) en yüksek sıkıştırmadır, ancak daha uzun sürer. İhtiyaçlarınız için ticareti kapatmak için sıkıştırma boyutu/zamanını ayarlamak üzere -1 ile -9 arasında açık bir sayı verebilirsiniz.

Umarım bu yardımcı olur.

+0

Gerçekten de, bir seferde silah sıkışması durumunda işe yaramayacak sort -mu kullanmak istiyorum. O (nlogn) öğesinden O (n) 'ye döner. –

+0

Normalde açık bir 'gzip -c -9' kullanıyorum ama sanırım işe yarayacak. –

+0

Yani büyük dosyalarınız var ve daha küçük dosyaları önceden sıralayarak ve daha sonra bunları birleştirerek süreci paralel hale getirmenin bir yolunu mu arıyorsunuz? Ve her bir küçük sıralama işlemine atayabileceğiniz çoklu CPU'larınız var mı? Zaman veya CPU veya ?? S.O.'da performans ayarlamalarıyla ilgilenen önemli sayıda insan var. Buna nasıl yaklaşılacağı konusunda daha iyi öneriler almak için kıyaslama, test etme, performans ayarlama için etiket ekleyebilirsiniz. İyi şanslar. – shellter

1

Dosya adlarındaki tek tırnak işaretleriyle, çok daha fazla çalışmanız gerekir.

İşte tek tırnak içine değişkenlerde eval 'ed alacak dosya adları (veya dosya yolları) içinde tek tırnak kaçmak için bir yol. sonunda onu çalıştırmak için `evet, komut dizesini oluşturmak için bir döngü gerekir ve ya` eval` veya `bash -c "$ cmd" -

(
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}" 
)