स्लुक-मोड में जाग?


16

उपकरण की तरह है sed, awkया perl -nउनके इनपुट एक की प्रक्रिया रिकॉर्ड एक समय में, रिकॉर्ड किया जा रहा लाइनों डिफ़ॉल्ट रूप से।

कुछ, जैसे awkके साथ RS, जीएनयू sedसाथ -zया perlके साथ -0oooएक अलग रिकॉर्ड विभाजक का चयन करके रिकॉर्ड का प्रकार बदल सकते हैं।

perl -nपूरे इनपुट कर सकते हैं (प्रत्येक व्यक्तिगत फ़ाइल जब कई फाइलें पास की जाती हैं) विकल्प के साथ एक एकल रिकॉर्ड-0777 (या -00377, 777 से अधिक किसी भी अष्टक संख्या के बाद विहित एक)। इसे ही वे स्लर्प मोड कहते हैं

कुछ इसी तरह से किया जा सकता awkहै RSया किसी अन्य तंत्र? awkप्रत्येक फ़ाइल की प्रत्येक पंक्ति के विपरीत प्रत्येक फ़ाइल सामग्री को एक पूरे के रूप में कहाँ संसाधित करता है?

जवाबों:


15

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

gawk, mawkया अन्य awkकार्यान्वयन जहां RSएक regexp हो सकता है।

उन कार्यान्वयनों में (के लिए mawk, सावधान रहें कि कुछ OS जैसे डेबियन जहाज को पुराने संस्करण के बजाय @ThomasDickey द्वारा बनाए गए आधुनिक संस्करण में रखा गया है ), यदि RSएक एकल वर्ण होता है, तो रिकॉर्ड विभाजक वह वर्ण होता है, या रिक्त awkहोने पर पैराग्राफ मोड में प्रवेश करता है। RSया RSअन्यथा एक नियमित अभिव्यक्ति के रूप में व्यवहार करता है ।

वहाँ समाधान एक नियमित अभिव्यक्ति का उपयोग करना है जो संभवतः मेल नहीं खा सकता है। कुछ की तरह मन के लिए आते हैं x^या $x( xशुरू होने से पहले, या अंत के बाद)। हालांकि कुछ (विशेषकर के साथ gawk) दूसरों की तुलना में अधिक महंगे हैं। अब तक, मैंने पाया है कि ^$सबसे कुशल एक है। यह केवल एक खाली इनपुट पर मेल कर सकता है, लेकिन तब मैच के लिए कुछ भी नहीं होगा।

तो हम कर सकते हैं:

awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

एक चेतावनी यह है कि यह खाली फाइलों को छोड़ देती है (इसके विपरीत perl -0777 -n)। इसके बजाय awkएक ENDFILEबयान में कोड डालकर जीएनयू के साथ संबोधित किया जा सकता है । लेकिन हमें $0एक BEGINFILE स्टेटमेंट में रीसेट करने की भी आवश्यकता है क्योंकि यह अन्यथा खाली फाइल को संसाधित करने के बाद रीसेट नहीं किया जाएगा:

gawk -v RS='^$' '
   BEGINFILE{$0 = ""}
   ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...

पारंपरिक awkकार्यान्वयन, POSIXawk

उन में, RSसिर्फ एक चरित्र है, उनके पास BEGINFILE/ नहीं है ENDFILE, उनके पास RTचर नहीं है , वे आम तौर पर एनयूएल चरित्र को संसाधित नहीं कर सकते हैं।

आपको लगता है कि RS='\0'तब काम कर सकता था, क्योंकि वैसे भी वे एनयूएल बाइट वाले इनपुट को संसाधित नहीं कर सकते हैं, लेकिन नहीं, RS='\0'पारंपरिक कार्यान्वयन में ऐसा माना जाता है RS=, जो पैराग्राफ मोड है।

एक समाधान एक चरित्र का उपयोग करने के लिए हो सकता है जो इनपुट में पाए जाने की संभावना नहीं है \1। मल्टीबाइट कैरेक्टर लोकेशन्स में, आप इसे बाइट-सीक्वेंस भी बना सकते हैं, $'\U10FFFE'जो यूटीएफ -8 लोकेशन्स की तरह कैरेक्टर नहीं बनाते या असाइन नहीं किए जाते हैं । हालांकि वास्तव में मूर्ख नहीं है और आपको खाली फाइलों के साथ भी समस्या है।

एक अन्य समाधान पूरे इनपुट को एक चर में संग्रहीत करना और अंत में कथन में इसे संसाधित करना हो सकता है। इसका मतलब है कि आप एक समय में केवल एक ही फ़ाइल को संसाधित कर सकते हैं:

awk '{content = content $0 RS}
     END{$0 = content
       printf "%s: <%s>\n", FILENAME, $0
     }' file

यह बराबर है sed:

sed '
  :1
  $!{
   N;b1
  }
  ...' file1

उस दृष्टिकोण के साथ एक और मुद्दा यह है कि यदि फ़ाइल एक नई पंक्ति में समाप्त नहीं हो रही थी (और खाली नहीं थी), एक अभी भी $0अंत में मनमाने ढंग से जोड़ा गया है (के साथ gawk, आप RTइसके बजाय काम करके चारों ओर काम करेंगे RS; ऊपर कोड)। एक लाभ यह है कि आपके पास फ़ाइल में लाइनों की संख्या का रिकॉर्ड NR/ में है FNR


अंतिम भाग के लिए के रूप में ("अगर फ़ाइल एक नई पंक्ति में समाप्त नहीं हो रही थी (और खाली नहीं थी), एक अभी भी मनमाने ढंग से $ 0 में अंत में जोड़ा जाता है"): पाठ फ़ाइलों के लिए, उन्हें समाप्त होने वाला माना जाता है नई पंक्ति। vi, उदाहरण के लिए, एक को जोड़ता है, और इस प्रकार जब आप इसे सहेजते हैं तो फ़ाइल को संशोधित करते हैं। टर्मिनेटिंग न्यूलाइन नहीं होने से कुछ कमांड अंतिम "लाइन" (उदा: wc) को छोड़ देती है, लेकिन अन्य अभी भी अंतिम लाइन को देखते हैं ... ymmv। आपका समाधान इसलिए मान्य है, imo, यदि आप पाठ फ़ाइलों का इलाज करने वाले हैं (जो कि संभवतः मामला है, क्योंकि awk पाठ प्रसंस्करण के लिए अच्छा है, लेकिन बायनेरिज़ के लिए इतना अच्छा नहीं है ^ ^)
ओलिवियर दुलक

1
सभी सीमाओं को खिसकाने की कोशिश करने से कुछ सीमाएँ प्रभावित हो सकती हैं ... ट्रेडिशनल अवेक जाहिरा तौर पर (एक?) एक लाइन पर 99 फ़ील्ड्स की सीमा होती है ... इसलिए आपको उस सीमा से बचने के लिए एक अलग FS का उपयोग करने की आवश्यकता हो सकती है, लेकिन हो सकता है कि आप यह भी सीमा है कि एक लाइन की कुल लंबाई (या पूरी बात, यदि आप इसे एक लाइन पर प्राप्त करने का प्रबंधन करते हैं) कितनी लंबी हो सकती है?
ओलिवियर दुलक

अंत में: (मूर्खतापूर्ण ...) हैक 1 पूरी फ़ाइल को पार्स करने के लिए हो सकता है और एक चार की तलाश कर सकता है जो कि वहां नहीं है, फिर tr '\n' 'thatchar' इसे फ़ाइल को awk, और tr 'thatchar' \n'आउटपुट में भेजने से पहले ? (आपको अभी भी यह सुनिश्चित करने के लिए एक नई लाइन संलग्न करने की आवश्यकता हो सकती है, जैसे कि मैंने ऊपर उल्लेख किया है, आपकी इनपुट फ़ाइल में एक समाप्ति वाली नई पंक्ति है: { tr '\n' 'missingchar' < thefile ; printf "\n" ;} | awk ..... | { tr 'missingchar' '\n' }(लेकिन अंत में एक '\ n' जोड़ें, जो आपको छुटकारा पाने की आवश्यकता हो सकती है ... शायद अंतिम ट्रे से पहले एक सीड जोड़ना? अगर वह ट्राइ नईलाइंस को समाप्त किए बिना फाइलों को स्वीकार करता है ...)
ओलिवियर दुलैक

@OlivierDulac, यदि हम NF या किसी भी क्षेत्र को एक्सेस कर रहे हैं, तो फ़ील्ड की संख्या पर सीमा केवल तभी लागू होगी। awkयदि हम नहीं करते तो विभाजन नहीं करते। कहा जा रहा है कि, /bin/awkसोलारिस 9 का भी नहीं (1970 के दशक के आधार पर) उस सीमा पर आधारित था, इसलिए मुझे यकीन नहीं है कि हम एक ऐसा खोज सकते हैं जो (अभी भी संभव है क्योंकि SVR4 के ऑव की सीमा 99 और nawk 199 थी, इसलिए यह है) संभवतया उस सीमा को उठाकर सूर्य द्वारा जोड़ा गया था और एसवीआर 4 आधारित अन्य एसकेआर में नहीं पाया जा सकता है, क्या आप +IX पर परीक्षण कर सकते हैं?)।
स्टीफन चेजलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.