खोल में कई फ़ाइलों के लिए पाइप


29

मेरे पास एक एप्लिकेशन है जो बड़ी मात्रा में डेटा का उत्पादन करेगा जिसे मैं डिस्क पर संग्रहीत नहीं करना चाहता हूं। एप्लिकेशन ज्यादातर डेटा को आउटपुट करता है जिसे मैं उपयोग नहीं करना चाहता, लेकिन उपयोगी जानकारी का एक सेट जिसे अलग-अलग फ़ाइलों में विभाजित किया जाना चाहिए। उदाहरण के लिए, निम्न आउटपुट दिया गया:

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

मैं इस तरह से तीन बार आवेदन चला सकता हूं:

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

यह मुझे वह मिलेगा जो मैं चाहता हूं, लेकिन इसमें बहुत समय लगेगा। मैं भी एक फ़ाइल के लिए सभी आउटपुट डंप करने और उस के माध्यम से पार्स नहीं करना चाहता।

क्या ऊपर दिखाए गए तीन ऑपरेशनों को इस तरह से संयोजित करने का कोई तरीका है कि मुझे केवल एक बार एप्लिकेशन चलाने की आवश्यकता है और अभी भी तीन अलग-अलग आउटपुट फाइलें मिल सकती हैं?

जवाबों:


78

यदि आपके पास टी है

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

( यहां से )

( प्रक्रिया प्रतिस्थापन के बारे में )


4
बहुत बढ़िया, यह भी प्रस्तुत किया जा सकता है:./app | tee >(grep A > A.out) >(grep B > B.out) | grep C > C.out
evilsoup

7
यह उत्तर वर्तमान में एकमात्र सटीक है, जिसे प्रश्न का मूल शीर्षक "कई प्रक्रियाओं के लिए पाइप" दिया गया है।
18

3
+1। यह सबसे आम तौर पर लागू होने वाला उत्तर है, क्योंकि यह इस तथ्य पर निर्भर नहीं करता है कि विशिष्ट फ़िल्टरिंग कमांड क्या था grep
रूतख

1
मैं इस बात पर सहमत हूं कि प्रश्न के लिए यह सबसे अच्छा जवाब है और इसे चिह्नित किया जाना चाहिए। समानांतर एक और समाधान है (जैसा कि पोस्ट किया गया है) लेकिन कुछ समयबद्ध तुलना करने से उपरोक्त उदाहरण अधिक कुशल है। यदि op के बजाय अत्यधिक cpu गहन संचालन जैसे एकाधिक फ़ाइल संपीड़न या कई mp3 रूपांतरण शामिल हैं, तो इसमें कोई संदेह नहीं है कि समानांतर समाधान अधिक प्रभावी साबित होना चाहिए।
AsymLabs

32

आप उपयोग कर सकते हैं awk

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

6
प्रश्न का शीर्षक कई प्रक्रियाओं पर पाइप है , यह उत्तर "पाइपिंग" (regex द्वारा प्रेषण) से कई फाइलों के बारे में है । चूंकि यह उत्तर स्वीकार किया गया था, इसलिए प्रश्न का शीर्षक उसी के अनुसार बदला जाना चाहिए।
16

@PauloMadeira आप सही हैं। आपको क्या लगता है एक बेहतर शीर्षक होगा?
sj755

मैंने "शेल में एकाधिक फ़ाइलों के लिए पाइप" एक बहुत छोटा संपादन सुझाया है, यह लंबित है, इसे देखें। अगर यह स्वीकार किया गया तो मैं टिप्पणी को हटाने की उम्मीद कर रहा था।
तीव्र

@PaooMadeira - मैंने शीर्षक बदल दिया है। अपना संपादन नहीं देखा, लेकिन आप सही हैं, यदि यह स्वीकृत उत्तर है तो शीर्षक में प्रक्रियाओं का उपयोग गलत था।
SLM

17

तुम भी अपने खोल पैटर्न मिलान क्षमताओं का उपयोग कर सकते हैं :

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

या और भी:

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

एक सुरक्षित तरीका जो बैकस्लैश और रेखाओं से शुरू हो सकता है -:

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

जैसा कि @StephaneChazelas टिप्पणियों में बताते हैं, यह बहुत कुशल नहीं है। सबसे अच्छा समाधान शायद @ AurélienOoms 'है


यही कारण है कि मान लिया गया इनपुट बैकस्लैश या रिक्त स्थान या वाइल्डकार्ड वर्णों, या लाइनों कि के साथ शुरू शामिल नहीं है -n, -e... यह भी यह प्रत्येक पंक्ति में कई सिस्टम कॉल (एक का मतलब है के रूप में बहुत अक्षम हो रहा है read(2)चरित्र प्रति, फ़ाइल खुला जा रहा है, लेखन प्रत्येक पंक्ति के लिए बंद ...)। आम तौर पर, while readगोले में पाठ को संसाधित करने के लिए छोरों का उपयोग करना खराब अभ्यास है।
स्टीफन चेज़लस

@StephaneChazelas मैंने अपना उत्तर संपादित किया। यह -nअब backslashes और आदि के साथ काम करना चाहिए । जहाँ तक मैं बता सकता हूँ दोनों संस्करण रिक्त के साथ ठीक काम करते हैं, हालांकि, क्या मैं गलत हूँ?
terdon

नहीं, पहला तर्क printfप्रारूप है। आपको वहाँ से अलग किए गए चर को छोड़ने का कोई कारण नहीं है।
स्टीफन चेजलस

यह बैश में भी टूट जाएगा (और अन्य गोले जो एक समान तरीके से क्रेस्टिंग का उपयोग करते हैं) यदि इनपुट में नल हैं।
क्रिस डाउन

9

यदि आपके पास कई कोर हैं और आप चाहते हैं कि प्रक्रियाएं समानांतर में हों, तो आप कर सकते हैं:

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

यह समांतर कोश में तीन प्रक्रियाएँ करेगा। यदि आप चाहते हैं कि कंसोल, या मास्टर फ़ाइल में कुछ आउटपुट हो, तो आउटपुट को कुछ क्रम में रखने का लाभ होता है, बल्कि इसे मिक्स करके।

जीएनयू उपयोगिता समानांतर ओले Tange से नाम के तहत सबसे रेपोस से प्राप्त किया जा सकता समानांतर या moreutils । स्रोत से प्राप्त किया जा सकता Savannah.gnu.org । इसके अलावा एक परिचयात्मक निर्देशात्मक वीडियो यहाँ है

परिशिष्ट

समानांतर के अधिक हाल के संस्करण का उपयोग करना (जरूरी नहीं कि आपके वितरण रेपो में संस्करण), आप अधिक सुरुचिपूर्ण निर्माण का उपयोग कर सकते हैं:

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

जो अलग-अलग कोर या थ्रेड्स में एक ./app और 3 समानांतर grep प्रक्रियाओं को चलाने के परिणाम को प्राप्त करता है (जैसा कि समानांतर स्वयं द्वारा निर्धारित किया गया है, -j3 को वैकल्पिक भी मानता है, लेकिन यह शिक्षाप्रद उद्देश्यों के लिए इस उदाहरण में आपूर्ति की गई है)।

समानांतर का नया संस्करण प्राप्त करके किया जा सकता है:

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

फिर सामान्य अनपैक, सीडी से समानांतर- {तिथि}, .configure && मेक, सुडो मेक इनस्टॉल। यह समानांतर, मैन पेज समानांतर और मैन पेज समानांतर_ट्रीम स्थापित करेगा।


7

यहाँ पर्ल में एक है:

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

... अगर <inपठनीय सभी तीन संगठनों को कुछ भी लिखे जाने से पहले अलग कर दिया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.