Pipa ke beberapa file di shell


29

Saya memiliki aplikasi yang akan menghasilkan sejumlah besar data yang tidak ingin saya simpan ke disk. Sebagian besar aplikasi mengeluarkan data yang tidak ingin saya gunakan, tetapi satu set informasi berguna yang harus dipisah menjadi file yang terpisah. Misalnya, diberikan output berikut:

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

Saya bisa menjalankan aplikasi tiga kali seperti ini:

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

Ini akan memberi saya apa yang saya inginkan, tetapi itu akan memakan waktu terlalu lama. Saya juga tidak ingin membuang semua output ke satu file dan menguraikannya.

Apakah ada cara untuk menggabungkan tiga operasi yang ditunjukkan di atas sedemikian rupa sehingga saya hanya perlu menjalankan aplikasi sekali dan masih mendapatkan tiga file output terpisah?

Jawaban:


78

Jika Anda memiliki tee

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

(dari sini )

( tentang substitusi proses )


4
Luar biasa, ini juga dapat diterjemahkan sebagai:./app | tee >(grep A > A.out) >(grep B > B.out) | grep C > C.out
evilsoup

7
Jawaban ini saat ini adalah satu-satunya yang akurat, mengingat judul asli pertanyaan itu "pipa ke banyak proses".
acelent

3
+1. Ini adalah jawaban yang paling umum berlaku, karena tidak bergantung pada fakta bahwa perintah penyaringan tertentu grep.
ruakh

1
Saya setuju bahwa ini adalah jawaban terbaik untuk pertanyaan yang diajukan dan harus ditandai demikian. Paralel adalah solusi lain (seperti yang diposting) tetapi setelah melakukan beberapa perbandingan waktunya, contoh di atas lebih efisien. Jika op sebaliknya melibatkan operasi yang sangat cpu intensif seperti kompresi beberapa file atau konversi beberapa mp3 maka tidak diragukan solusi paralel harus terbukti lebih efektif.
AsymLabs

32

Anda dapat gunakan awk

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

6
Judul pertanyaan adalah pipa ke beberapa proses , jawaban ini adalah tentang "pemipaan" (dispatching by regex) ke banyak file . Karena jawaban ini diterima, judul pertanyaan harus diubah sesuai.
acelent

@PauloMadeira Anda benar. Menurut Anda apa gelar yang lebih baik?
sj755

Saya telah menyarankan suntingan yang sangat kecil "Pipa ke beberapa file di shell", menunggu revisi, periksa. Saya berharap untuk menghapus komentar jika diterima.
acelent

@PauloMadeira - Saya sudah mengubah judulnya. Tidak melihat hasil edit Anda, tetapi Anda benar, penggunaan proses dalam judul tidak benar jika ini adalah jawaban yang diterima.
slm

17

Anda juga bisa menggunakan kemampuan pencocokan pola shell Anda :

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

Atau bahkan:

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

Cara yang lebih aman yang dapat menangani garis miring terbalik dan garis dimulai dengan -:

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

Seperti yang ditunjukkan @StephaneChazelas dalam komentar, ini tidak terlalu efisien. Solusi terbaik mungkin adalah @ AurélienOoms ' .


Itu mengasumsikan input tidak mengandung garis miring terbalik atau karakter kosong atau wildcard, atau baris yang dimulai dengan -n, -e... Itu juga akan sangat tidak efisien karena itu berarti beberapa panggilan sistem per baris (satu read(2)per karakter, file terbuka, menulis ditutup untuk setiap baris ...). Secara umum, menggunakan while readloop untuk memproses teks dalam shell adalah praktik yang buruk.
Stéphane Chazelas

@StephaneChazelas saya mengedit jawaban saya. Seharusnya bekerja dengan backslash dan -nlain - lain sekarang. Sejauh yang saya tahu kedua versi bekerja OK dengan kosong, apakah saya salah?
terdon

Tidak, argumen pertama printfadalah format. Tidak ada alasan untuk membuat Anda variabel tidak dikutip di sana.
Stéphane Chazelas

Ini juga akan pecah di bash (dan shell lain yang menggunakan cstring dengan cara yang sama) jika ada nulls di input.
Chris Down

9

Jika Anda memiliki banyak inti dan Anda ingin prosesnya paralel, Anda dapat melakukan:

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

Ini akan menelurkan tiga proses dalam inti paralel. Jika Anda ingin ada output ke konsol, atau file master, itu memiliki keuntungan menjaga output dalam urutan tertentu, daripada mencampurnya.

Paralel utilitas gnu dari Ole Tange dapat diperoleh dari sebagian besar repo dengan nama paralel atau lebih . Sumber dapat diperoleh dari Savannah.gnu.org . Juga ada video pengajaran pengantar di sini .

Tambahan

Menggunakan versi paralel yang lebih baru (tidak harus versi dalam repo distribusi Anda), Anda dapat menggunakan konstruk yang lebih elegan:

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

Yang mencapai hasil menjalankan satu ./app dan 3 proses grep paralel dalam inti atau utas yang terpisah (sebagaimana ditentukan oleh paralel itu sendiri, juga menganggap -j3 sebagai opsional, tetapi diberikan dalam contoh ini untuk tujuan instruktif).

Versi paralel yang lebih baru dapat diperoleh dengan melakukan:

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

Kemudian, buka paket yang biasa, cd ke parallel- {date}, ./configure && make, sudo make install. Ini akan menginstal parallel, man page parallel dan man page parallel_tutorial.


7

Inilah satu di Perl:

./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

... jika <indapat dibaca, ketiga outfiles akan dipotong sebelum sesuatu dituliskan kepada mereka.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.