Kabuktaki birden fazla dosyaya yön verin


29

Diske depolamak istemediğim büyük miktarda veri üretecek bir uygulamam var. Uygulama çoğunlukla kullanmak istemediğim, ancak ayrı dosyalara bölünmesi gereken birtakım yararlı bilgiler verir. Örneğin, aşağıdaki çıktı verilir:

JUNK
JUNK
JUNK
JUNK
A 1
JUNK
B 5
C 1
JUNK

Uygulamayı üç defa çalıştırabilirim:

./app | grep A > A.out
./app | grep B > B.out
./app | grep C > C.out

Bu istediğimi elde ederdi, ama çok uzun sürdü. Ayrıca tüm çıktıları tek bir dosyaya dökmek ve bunun üzerinden ayrıştırmak istemiyorum.

Yukarıda gösterilen üç işlemi uygulamanın sadece bir kez çalıştırmam ve hala üç ayrı çıktı dosyası almamı sağlayacak şekilde birleştirmenin bir yolu var mı?

Yanıtlar:


78

Eğer tee

./app | tee >(grep A > A.out) >(grep B > B.out) >(grep C > C.out) > /dev/null

( buradan )

( işlem değişikliği hakkında )


4
Awesome, bu şu şekilde de olabilir:./app | tee >(grep A > A.out) >(grep B > B.out) | grep C > C.out
evilsoup

7
Bu cevap şu anda sorunun asıl adı verilen "birden fazla işleme yöneltilen boru" olan tek kesin cevap.
acelent

3
+1. Bu, en genel olarak uygulanabilir cevaptır, çünkü spesifik filtreleme komutunun olduğu gerçeğine bağlı değildir grep.
ruakh

1
Bunun, sorulan soru için en iyi cevap olduğu ve bu şekilde işaretlenmesi gerektiği konusunda hemfikirdim. Paralel başka bir çözümdür (yayınlandığı gibi), ancak bazı zamanlanmış karşılaştırmalar yapmış olmak yukarıdaki örnek daha verimlidir. Eğer op bunun yerine, çoklu dosya sıkıştırma veya çoklu mp3 dönüştürme gibi yüksek cpu yoğun işlemler içeriyorsa, paralel çözümün daha etkili olduğu kanıtlanmalıdır.
AsymLabs

32

Kullanabilirsiniz awk

./app | awk '/A/{ print > "A.out"}; /B/{ print > "B.out"}; /C/{ print > "C.out"}'

6
Sorunun başlığı çoklu işlemlere yönelik bir boru , bu cevap birden fazla dosyaya "boru" (regex ile gönderme) hakkında . Bu cevap kabul edildiğinden, sorunun başlığı buna göre değiştirilmelidir.
acelent

@PauloMadeira Haklısın. Sizce daha iyi bir başlık olabilir mi?
sj755

Çok küçük bir düzenleme önerdim "Kabuktaki birden fazla dosyaya yönlendir", gözden geçirme beklemede. Kabul edildiyse yorumu kaldırmayı bekliyordum.
acelent

@ PauloMadeira - Başlığı değiştirdim. Düzenlemenizi görmediniz, ancak haklısınız, kabul edilen cevap buysa, başlıktaki işlemlerin kullanımı yanlıştı.
slm

17

Kabuğunuzun kalıp eşleştirme yeteneklerini de kullanabilirsiniz :

./app | while read line; do 
     [[ "$line" =~ A ]] && echo $line >> A.out; 
     [[ "$line" =~ B ]] && echo $line >> B.out; 
     [[ "$line" =~ C ]] && echo $line >> C.out; 
 done

Ya da:

./app | while read line; do for foo in A B C; do 
     [[ "$line" =~ "$foo" ]] && echo $line >> "$foo".out; 
  done; done

Ters eğik çizgiler ve çizgilerle baş edebilecek daha güvenli bir yol -:

./app | while IFS= read -r line; do for foo in A B C; do 
     [[ "$line" =~ "$foo" ]] && printf -- "$line\n" >> "$foo".out; 
  done; done

@StephaneChazelas yorumlarda da belirtildiği gibi, bu çok verimli değildir. En iyi çözüm muhtemelen @ AurélienOoms'dur .


Girdide ters eğik çizgi veya boşluk veya joker karakter veya satır ile başlayan satır içermediğini varsayar -n, -e... Her satırda birkaç sistem çağrısı ( read(2)karakter başına bir tane , açık, yazma her satır için kapalı ...). Genel olarak, while readkabukları içindeki metni işlemek için döngüler kullanmak kötü bir uygulamadır.
Stéphane Chazelas

@StephaneChazelas Cevabımı düzenledim. Şimdi ters eğik çizgi -nvb. İle çalışması gerekir . Her iki sürümde de söyleyebildiğim kadarıyla tamam boşluklarla tamam, yanlış mıyım?
terdon

Hayır, ilk argüman printfformat. Seni değişkenler içinde alıntı yapmamak için hiçbir sebep yok.
Stéphane Chazelas 27:13

Girdide boş değerler varsa, bash (ve aynı şekilde cstrings kullanan diğer kabukları) da kırılır.
Chris Down,

9

Birden fazla çekirdeğiniz varsa ve işlemlerin paralel olmasını istiyorsanız, şunları yapabilirsiniz:

parallel -j 3 -- './app | grep A > A.out' './app | grep B > B.out' './app | grep C > C.out'

Bu, paralel çekirdekte üç süreci doğurur. Konsolun bir çıktısı veya bir ana dosya olmasını istiyorsanız, çıktının bir miktar sırayla tutulması, karıştırmanın avantajı vardır.

Ole Tange'den paralel olan gnu faydası , paralel veya moreutils adı altında çoğu repodan elde edilebilir . Kaynak Savannah.gnu.org adresinden elde edilebilir . Ayrıca bir tanıtım videosu da burada .

ek

Paralelin en yeni sürümünü (mutlaka dağıtım reponuzdaki sürümü değil) kullanarak daha zarif yapıyı kullanabilirsiniz:

./app | parallel -j3 -k --pipe 'grep {1} >> {1}.log' ::: 'A' 'B' 'C'

Bir ./app ve 3 paralel grep işleminin ayrı çekirdeklerde veya dişlerde çalıştırılması sonucunu elde eden (paralelin kendisi tarafından belirlendiği gibi, -j3'ün isteğe bağlı olduğunu da düşünün, ancak bu örnekte öğretici amaçlar için verilmiştir).

Paralelin daha yeni bir sürümü şu şekilde elde edilebilir:

wget http://ftpmirror.gnu.org/parallel/parallel-20131022.tar.bz2

Sonra her zamanki paketten çıkarın, cd to parallel- {date}, ./configure && make, sudo make install. Bu paralel, man sayfa paralel ve man sayfa parallel_tutorial'ı yükleyecektir.


7

İşte Perl'de bir tane:

./app | perl -ne 'BEGIN {open(FDA, ">A.out") and 
                         open(FDB, ">B.out") and 
                         open(FDC, ">C.out") or die("Cannot open files: $!\n")} 
                  print FDA $_ if /A/; print FDB $_ if /B/; print FDC $_ if /C/'

1
sed -ne/A/w\ A.out -e/B/w\ B.out -e/C/p <in >C.out

... <inokunabilirse, üç dosya da bir şey yazılmadan önce kesilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.