फ़ाइल को दो भागों में विभाजित करें, एक पैटर्न पर


14

एक पैटर्न में एक बड़ी फ़ाइल को दो भागों में कैसे विभाजित किया जाए?

एक उदाहरण दिया file.txt:

ABC
EFG
XYZ
HIJ
KNL

मैं इस फाइल को XYZइस तरह से विभाजित करना चाहता हूं file1जिसमें लाइन अप और टू XYZऔर बाकी लाइनें शामिल हों file2


XYZलाइन को आउटपुट में शामिल किया जाना चाहिए या नहीं?
terdon

@terdon मेरे मामले में कोई "XYZ" लाइन फ़ाइल 2 का हिस्सा नहीं होनी चाहिए। लेकिन अगर आपके पास ऐसा करने का कोई तरीका है तो कृपया जवाब देने के लिए जोड़ें। यह कुछ अन्य मामलों में उपयोगी हो सकता है।
d.putto

काफी हो गया, किया।
terdon

जवाबों:


10

साथ awkआप कर सकते हैं:

awk '{print >out}; /XYZ/{out="file2"}' out=file1 largefile


स्पष्टीकरण: पहला awkतर्क ( out=file1) फ़ाइल नाम के साथ एक चर को परिभाषित करता है जिसका उपयोग आउटपुट के लिए किया जाएगा जबकि बाद के तर्क ( largefile) को संसाधित किया जाता है। awkकार्यक्रम चर द्वारा निर्दिष्ट फ़ाइल के लिए सभी लाइनों प्रिंट होगा out( {print >out})। यदि पैटर्न XYZमिल जाएगा आउटपुट चर को नई फ़ाइल ( {out="file2}") में इंगित करने के लिए पुनर्परिभाषित किया जाएगा जो बाद की डेटा लाइनों को प्रिंट करने के लिए लक्ष्य के रूप में उपयोग किया जाएगा।

संदर्भ:


14

यह इसके लिए एक काम है csplit:

csplit -sf file -n 1 large_file /XYZ/

silently फ़ाइल को विभाजित करेगा , पूर्व fix के साथ टुकड़े बनायेगा fileऔर nएकल अंक, उदाहरण file0आदि का उपयोग करके umbered । ध्यान दें कि उपयोग /regex/करने से विभाजित होगा, लेकिन उस रेखा से मेल नहीं खाता है जिसमें मेल खाता है regex। अप करने के लिए विभाजित करने के लिए और लाइन मिलान सहित regexजोड़ने एक +1ऑफसेट:

csplit -sf file -n 1 large_file /XYZ/+1

यह दो फाइलें बनाता है, file0और file1। यदि आपको उनके नाम की आवश्यकता है file1और file2आप हमेशा csplitकमांड में एक खाली पैटर्न जोड़ सकते हैं और पहली फाइल को हटा सकते हैं:

csplit -sf file -n 1 large_file // /XYZ/+1

बनाता है file0, file1और file2लेकिन file0खाली है ताकि आप उसे सुरक्षित निकाल सकते हैं:

rm -f file0

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

6

ऊपर दिए गए एक उत्तर में एक आधुनिक के साथ एक kshशैल संस्करण (अर्थात बिना sed)sed

{ read in <##XYZ ; print "$in" ; cat >file2 ;} <largefile >file1


और kshअकेले में एक और संस्करण (यानी भी omitting cat):

{ read in <##XYZ ; print "$in" ; { read <##"" ;} >file2 ;} <largefile >file1


(शुद्ध kshसमाधान काफी अच्छा प्रतीत होता है; 2.4 जीबी परीक्षण फ़ाइल पर इसे 19-21 सेकंड की आवश्यकता थी, जबकि 39-47 सेकंड sed/ catआधारित दृष्टिकोण के साथ)।


यह बहुत तेज है। लेकिन मुझे नहीं लगता कि आपको इसकी आवश्यकता है readऔर printआपको इसे केवल अपने स्वयं के आउटपुट पर जाने देना चाहिए। प्रदर्शन बेहतर हो जाता है यदि आप एएसटी टूलकिट को पूरी तरह से बनाते हैं और सभी kshसंकलित निर्माणों को प्राप्त करते हैं - यह मेरे लिए अजीब है जो sedवास्तव में उनमें से एक नहीं है। लेकिन जैसे सामान के साथ while <file doमुझे लगता है कि आपको sedइतनी ज़रूरत नहीं है ...
mikeserv

हालांकि मैं उत्सुक हूं - awkआपके बेंचमार्क में कैसा प्रदर्शन रहा? और जब मुझे पूरा यकीन है कि kshसंभावना हमेशा इस लड़ाई को जीतेगी, अगर आप एक GNU का उपयोग कर रहे हैं, तो आप sedबहुत निष्पक्ष नहीं हो रहे हैं sed- GNU के -unbuffered एक गरीब-गरीब दृष्टिकोण है जो वर्णनकर्ता की ऑफसेट को सुनिश्चित करता है कि जहां कार्यक्रम छोड़ दिया गया है यह - कार्यक्रम के नियमित संचालन को धीमा करने की कोई आवश्यकता नहीं होनी चाहिए - बफरिंग ठीक है - सभी को sedकरना होगा जब समाप्त हो जाए तो विवरणक को lseek करना होगा। जिस कारण से GNU उस मानसिकता को उलट देता है।
15

@mikeserv; पुनर्निर्देशन पैटर्न का मिलान तब तक किया जाता है जब तक कि पैटर्न नहीं मिल जाता है, और पाया गया पैटर्न के साथ लाइन को प्रिंट नहीं किया जाएगा यदि स्पष्ट रूप से चित्रित नहीं किया गया है। (कम से कम जिसने मेरा परीक्षण दिखाया।) ध्यान दें कि कोई नहीं है while; मुद्रण को मूल रूप से <##पुनर्निर्देशन ऑपरेटर के परिभाषित दुष्प्रभाव के रूप में किया जाता है । और केवल मिलान रेखा को मुद्रण की आवश्यकता होती है। (इस तरह से शेल फीचर का कार्यान्वयन incl./excl के समर्थन के लिए सबसे अधिक लचीला है।) एक स्पष्ट whileलूप मैं महत्वपूर्ण धीमी होने की उम्मीद करूँगा (लेकिन जाँच नहीं की गई)।
जेनिस

1
@mikeserv; आह ठीक है। BTW, मैं सिर्फ के headबजाय की कोशिश की read; यह केवल थोड़ा धीमा लगता है, लेकिन यह बहुत ही कठिन है { head -1 <##XYZ ; { read <##"" ;} >file4 ;} <largefile >file3:।
Janis

1
@mikeserv; अच्छी बात; यह नहीं था लेकिन जब मैं बिलिन को सक्रिय करता हूं (बस किए गए और परिणामों की जांच की गई) यह एक ही संख्या है, अजीब है। (शायद कुछ फ़ंक्शन पढ़ने की तुलना में ओवरहेड कहते हैं?)
Janis

6
{ sed '/XYZ/q' >file1; cat >file2; } <infile

GNU के साथ sedआपको -unbuffered स्विच का उपयोग करना चाहिए । sedहालांकि अधिकांश अन्य को सिर्फ काम करना चाहिए।

XYZ को छोड़ने के लिए ...

{ sed -n '/XYZ/q;p'; cat >file2; } <infile >file1


1

एक आसान हैक या तो STDOUT या STDERR को प्रिंट करना है, यह इस बात पर निर्भर करता है कि लक्ष्य पैटर्न का मिलान किया गया है या नहीं। फिर आप अपने अनुसार आउटपुट को पुनर्निर्देशित करने के लिए शेल के पुनर्निर्देशन ऑपरेटरों का उपयोग कर सकते हैं । उदाहरण के लिए, पर्ल में, इनपुट फ़ाइल को कहा जाता है fऔर दो आउटपुट फाइल f1और f2:

  1. विभाजन पैटर्न से मेल खाने वाली रेखा के बारे में:

    perl -ne 'if(/XYZ/){$a=1; next} ; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2
  2. मिलान लाइन सहित:

    perl -ne '$a=1 if /XYZ/; $a==1 ? print STDERR : print STDOUT;' f >f1 2>f2

वैकल्पिक रूप से, विभिन्न फ़ाइल हैंडल पर प्रिंट करें:

  1. विभाजन पैटर्न से मेल खाने वाली रेखा के बारे में:

    perl -ne 'BEGIN{open($fh1,">","f1");open($fh2,">","f2");}
    if(/XYZ/){$a=1; next}$a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
    
  2. मिलान लाइन सहित:

    perl -ne 'BEGIN{open($fh1,">","f1"); open($fh2,">","f2");}
              $a=1 if /XYZ/; $a==1 ? print $fh1 "$_" : print $fh2 "$_";' f
    
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.