sed: पूरी फाइल को सिंगल-लाइन इनपुट पर विफल हुए बिना पैटर्न स्पेस में पढ़ें


9

पैटर्न की जगह में एक पूरी फ़ाइल पढ़ना, newlines, और c को प्रतिस्थापित करने के लिए उपयोगी है। और निम्नलिखित की सलाह देने वाले कई उदाहरण हैं:

sed ':a;N;$!ba; [commands...]'

हालाँकि, यह विफल रहता है यदि इनपुट में केवल एक पंक्ति है।

एक उदाहरण के रूप में, दो लाइन इनपुट के साथ, हर लाइन प्रतिस्थापन कमांड के अधीन है:

$ echo $'abc\ncat' | sed ':a;N;$!ba; s/a/xxx/g'
xxxbc
cxxxt

लेकिन, सिंगल लाइन इनपुट के साथ, कोई प्रतिस्थापन नहीं किया जाता है:

$ echo 'abc' | sed ':a;N;$!ba; s/a/xxx/g'
abc

एक sedबार में सभी इनपुट को पढ़ने के लिए कोई कमांड कैसे लिखता है और यह समस्या नहीं है?


मैंने आपके प्रश्न को संपादित किया ताकि उसमें एक वास्तविक प्रश्न हो। यदि आप चाहें तो अन्य उत्तरों की प्रतीक्षा कर सकते हैं लेकिन अंत में स्वीकार किए गए अनुसार सर्वोत्तम उत्तर को चिह्नित करें (उत्तर के बाईं ओर पाइप बटन देखें, ऊपर-नीचे तीर बटन के ठीक नीचे)।
जॉन १०२४

@ John1024 धन्यवाद, एक उदाहरण के लिए अच्छा है। इस तरह की बात को याद दिलाना मुझे याद दिलाता है कि "सब कुछ गलत है", लेकिन मुझे खुशी है कि हममें से कुछ ने हार नहीं मानी है। :}
डिकेट्र

2
एक तीसरा विकल्प है! GNU के sed -zविकल्प का उपयोग करें । यदि आपकी फ़ाइल में कोई समस्या नहीं है, तो यह फ़ाइल के अंत तक पढ़ेगी! इस से मिला: stackoverflow.com/a/30049447/582917
CMCDragonkai

जवाबों:


13

सभी प्रकार के कारण हैं कि एक पूरी फ़ाइल को पैटर्न स्पेस में पढ़ना गलत क्यों हो सकता है। अंतिम पंक्ति के आसपास के प्रश्न में तर्क समस्या एक आम बात है। यह sed's रेखा चक्र से संबंधित है - जब कोई और रेखाएँ नहीं होती हैं और sedEOF से इसका सामना होता है - यह प्रसंस्करण से बाहर निकलता है। और इसलिए यदि आप अंतिम पंक्ति में हैं और आप sedएक और प्राप्त करने का निर्देश देते हैं तो यह वहीं रुकने वाला है और अधिक नहीं।

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

कई समान उपकरण हैं जो पूर्ण फ़ाइल ब्लॉक को संभालने के लिए बेहतर सुसज्जित हैं। edऔर ex, उदाहरण के लिए, क्या sedकर सकते हैं और क्या समान सिंटैक्स के साथ कर सकते हैं - और भी बहुत कुछ के अलावा - लेकिन यह इनपुट आउटपुट पर केवल संचालन के बजाय इसे आउटपुट में परिवर्तित करते हुए sed, वे फ़ाइल-सिस्टम में अस्थायी बैकअप फ़ाइलों को बनाए रखते हैं । उनका काम आवश्यकतानुसार डिस्क से बफ़र किया जाता है, और वे फ़ाइल के अंत में अचानक नहीं छोड़ते हैं (और बफर स्ट्रेन के तहत बहुत कम बार निहित होते हैं) । इसके अलावा वे कई उपयोगी कार्यों की पेशकश करते हैं, जो sedनहीं है - इस प्रकार का कि एक धारा के संदर्भ में समझ में नहीं आता है - जैसे लाइन के निशान, पूर्ववत, नामित बफ़र्स, सम्मिलित हों, और बहुत कुछ।

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

उस अंतिम बिंदु के बारे में, जिस तरह से: जब तक मैं समझता हूं कि उदाहरण का s/a/A/gमामला बहुत ही सरल उदाहरण है और संभवतः वह वास्तविक स्क्रिप्ट नहीं है जिसके लिए आप एक इनपुट में इकट्ठा करना चाहते हैं, तो हो सकता है कि आप खुद को परिचित करने के लिए इसे अपने लायक समझ सकें। y///। यदि आप अक्सर अपने आप को gएक दूसरे के लिए एकल चरित्र का स्थानापन्न पाते हैं , तो yयह आपके लिए बहुत उपयोगी हो सकता है। यह एक प्रतिस्थापन के विपरीत एक परिवर्तन है और यह बहुत जल्दी है क्योंकि यह एक रेगेक्स नहीं है। यह बाद का बिंदु भी इसे उपयोगी बना सकता है जब खाली //पतों को संरक्षित करने और दोहराने का प्रयास किया जाता है क्योंकि यह उन्हें प्रभावित नहीं करता है लेकिन उनके द्वारा प्रभावित हो सकता है। किसी भी मामले में, y/a/A/उसी को पूरा करने का एक अधिक सरल साधन है - और स्वैप संभव है जैसे:y/aA/Aa/ जो एक दूसरे के लिए एक पंक्ति के रूप में सभी ऊपरी / निचले हिस्से को इंटरचेंज करेगा।

आपको यह भी ध्यान देना चाहिए कि आप जिस व्यवहार का वर्णन करते हैं वह वास्तव में वैसा नहीं है जैसा कि होना चाहिए।

जीएनयू की ओर info sedसे कम से कम खरीद वाले खंड में:

  • N अंतिम पंक्ति पर कमांड

    • sedजब Nकोई फ़ाइल की अंतिम पंक्ति पर आदेश जारी किया जाता है , तो कुछ भी छपाई के बिना बाहर निकलने के अधिकांश संस्करण । sedजब तक कि -nकमांड स्विच को निर्दिष्ट नहीं किया गया है , तब तक बाहर निकलने से पहले GNU पैटर्न स्पेस प्रिंट करता है। यह चुनाव डिजाइन द्वारा है।

    • उदाहरण के लिए, का व्यवहार sed N foo barइस बात पर निर्भर करेगा कि फू की सम या विषम संख्या है। या, जब एक पैटर्न मैच के बाद अगली कुछ पंक्तियों को पढ़ने के लिए एक स्क्रिप्ट लिख रहे हैं, तो पारंपरिक कार्यान्वयन sedआपको /foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }सिर्फ कुछ के बजाय कुछ लिखने के लिए मजबूर करेंगे /foo/{ N;N;N;N;N;N;N;N;N; }

    • किसी भी मामले में, सबसे सरल समाधान उन $d;Nलिपियों में उपयोग करना है जो पारंपरिक व्यवहार पर निर्भर करते हैं, या POSIXLY_CORRECTचर को गैर-रिक्त मान पर सेट करते हैं ।

POSIXLY_CORRECTवातावरण चर उल्लेख किया गया है क्योंकि POSIX निर्दिष्ट करता है कि अगर sedमुठभेड़ों EOF जब प्रयास करते समय कोई Nयह उत्पादन के बिना छोड़ देना चाहिए, लेकिन जीएनयू संस्करण जानबूझकर इस मामले में मानक के साथ टूट जाता है। यह भी ध्यान दें कि व्यवहार को इस धारणा के ऊपर उचित ठहराया जाता है कि त्रुटि मामला स्ट्रीम-एडिटिंग में से एक है - स्मृति में पूरी फ़ाइल को स्लैपिंग नहीं करना।

मानक परिभाषित करता है Nके व्यवहार इस प्रकार:

  • N

    • मूल सामग्री से संलग्न सामग्री को अलग करने के लिए \nएम्बेडेड स्पेस का उपयोग करके पैटर्न स्पेस के लिए इनपुट की अगली पंक्ति को कम करें, इसकी समाप्ति ईलाइन को लागू करें \n। ध्यान दें कि वर्तमान लाइन संख्या बदल जाती है।

    • यदि इनपुट की कोई अगली पंक्ति उपलब्ध नहीं है, तो Nकमांड क्रिया स्क्रिप्ट के अंत में शाखा जाएगी और एक नया चक्र शुरू किए बिना या पैटर्न स्पेस को मानक आउटपुट पर कॉपी किए बिना छोड़ दिया जाएगा।

उस नोट पर, प्रश्न में प्रदर्शित कुछ अन्य जीएनयू-आईएमएस हैं - विशेष रूप से :लेबल, bरंच और {फ़ंक्शन-संदर्भ कोष्ठक का उपयोग }। अंगूठे के एक नियम के रूप में कोई भी sedआदेश जो एक मनमाना पैरामीटर स्वीकार करता \nहै, उसे स्क्रिप्ट में एक ewline पर परिसीमन करने के लिए समझा जाता है । तो आज्ञा ...

:arbitrary_label_name; ...
b to_arbitrary_label_name; ...
//{ do arbitrary list of commands } ...

... उन सभी के sedकार्यान्वयन के आधार पर गलत तरीके से प्रदर्शन की संभावना है जो उन्हें पढ़ते हैं। संभवतः उन्हें लिखा जाना चाहिए:

...;:arbitrary_label_name
...;b to_arbitrary_label_name
//{ do arbitrary list of commands
}

उसी के लिए सच है r, w, t, a, i, और c (और शायद कुछ और है कि मैं इस समय भूल रहा) । लगभग हर मामले में उन्हें भी लिखा जा सकता है:

sed -e :arbitrary_label_name -e b\ to_arbitary_label_name -e \
    "//{ do arbitrary list of commands" -e \}

... जहां नया -eक्लेक्शन स्टेटमेंट ईलाइन डेलिमिटर के लिए खड़ा है \n। तो जहां जीएनयू infoपाठ एक पारंपरिक sedकार्यान्वयन आपको यह करने के लिए मजबूर करेगा :

/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }

... बल्कि होना चाहिए ...

/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N
}

... बेशक, यह सच नहीं है। इस तरह से स्क्रिप्ट लिखना थोड़ा मूर्खतापूर्ण है। ऐसा करने के बहुत अधिक सरल साधन हैं, जैसे:

printf %s\\n foo . . . . . . |
sed -ne 'H;/foo/h;x;//s/\n/&/3p;tnd
         //!g;x;$!d;:nd' -e 'l;$a\' \
     -e 'this is the last line' 

... जो प्रिंट:

foo
.
.
.
foo\n.\n.\n.$
.$
this is the last line

... क्योंकि tअधिकांश कमांड - जैसे अधिकांश sedकमांड - अपने रिटर्न रजिस्टर को रीफ्रेश करने के लिए लाइन साइकल पर निर्भर करता है और यहां लाइन साइकल को अधिकतर काम करने की अनुमति है। जब आप किसी फ़ाइल को खिसकाते हैं, तो यह एक और ट्रेडऑफ़ है - लाइन चक्र कभी भी ताज़ा नहीं होता है, और इसलिए कई परीक्षण असामान्य रूप से व्यवहार करेंगे।

उपरोक्त आदेश अधिक-पहुंच वाले इनपुट का जोखिम नहीं उठाता है क्योंकि यह जो कुछ पढ़ता है उसे सत्यापित करने के लिए बस कुछ सरल परीक्षण करता है। साथ Hपुराने सभी लाइनों पकड़ अंतरिक्ष के साथ जोड़ दिया जाता है, लेकिन अगर एक पंक्ति से मेल खाती /foo/यह अधिलेखित कर देता है hपुराने अंतरिक्ष। बफ़र्स को अगले ई xबदल दिया जाता है, और एक सशर्त s///ubstration का प्रयास किया जाता है यदि बफर की सामग्री को //संबोधित किया गया अंतिम पैटर्न। दूसरे शब्दों //s/\n/&/3pमें, अपने साथ होल्ड स्पेस में तीसरी न्यूलाइन को बदलने का प्रयास करता है और यदि वर्तमान में मैच हो रहा है तो स्पेस को प्रिंट कर सकता है /foo/। अगर वह ओ.टी. ईटेल लेबल के tलिए स्क्रिप्ट शाखाओं को सफल करता है - जो एक ook करता है और स्क्रिप्ट को लपेटता है।ndl

इस मामले में कि दोनों /foo/और एक तीसरी न्यूलाइन को होल्ड स्पेस में एक साथ मिलान नहीं किया जा सकता है, फिर //!gबफ़र /foo/को मेल नहीं होने पर बफर को अधिलेखित कर देगा , या, यदि यह मिलान किया जाता है, तो यह बफ़र को अधिलेखित कर देगा यदि एक \nईव्लीन मेल नहीं खाता है (/foo/ ताकि साथ बदल रहा है खुद) । यह थोड़ा सूक्ष्म परीक्षण बफर को बिना किसी खिंचाव के लंबे समय तक भरने से रोकता है /foo/और यह सुनिश्चित करता है कि इनपुट पर ढेर न होने के कारण प्रक्रिया तेज़ हो। नो /foo/या //s/\n/&/3pफेल केस में फॉलो करने पर बफ़र्स को फिर से स्वैप किया जाता है और हर लाइन को डिलीट कर दिया जाता है।

वह अंतिम - अंतिम पंक्ति $!d- एक सरल प्रदर्शन है कि कैसे एक शीर्ष-डाउन sedस्क्रिप्ट को आसानी से कई मामलों को संभालने के लिए बनाया जा सकता है। जब आपकी सामान्य विधि सबसे सामान्य के साथ शुरू होने वाले अवांछित मामलों को दूर करने के लिए है और सबसे विशिष्ट की ओर काम कर रही है, तो किनारे के मामलों को और अधिक आसानी से नियंत्रित किया जा सकता है, क्योंकि उन्हें आपके अन्य वांछित डेटा के साथ स्क्रिप्ट के अंत तक गिरने की अनुमति है यह सब आप चाहते हैं केवल डेटा के साथ छोड़ दिया जाता है लपेटता है। एक बंद लूप से ऐसे किनारे के मामलों को लाने के लिए हालांकि यह करना अधिक कठिन हो सकता है।

और इसलिए यहां मुझे आखिरी बात कहनी है: यदि आपको वास्तव में एक पूरी फ़ाइल में खींचना है, तो आप इसे करने के लिए लाइन चक्र पर भरोसा करके थोड़ा कम काम करने के लिए खड़े हो सकते हैं। आमतौर पर आप लुकहेड के लिए एक्सटN और nएक्सट का उपयोग करते हैं - क्योंकि वे लाइन चक्र के आगे बढ़ते हैं। एक लूप के भीतर बंद लूप को अनावश्यक रूप से लागू करने के बजाय - जैसे कि लाइन चक्र वैसे भी एक साधारण पढ़ा हुआ लूप है - यदि आपका उद्देश्य केवल इनपुट को अंधाधुंध रूप से इकट्ठा करना है, तो संभवतः ऐसा करना आसान है:sed

sed 'H;1h;$!d;x;...'

... जो पूरी फ़ाइल को इकट्ठा करेगा या कोशिश करना बंद कर देगा।


एक साइड नोट के बारे में Nऔर अंतिम पंक्ति व्यवहार ...

जब मेरे पास परीक्षण करने के लिए मेरे पास उपलब्ध उपकरण नहीं हैं, तो विचार करें कि Nजब रीडिंग और इन-प्लेस संपादन अलग तरीके से व्यवहार करता है अगर संपादित की गई फ़ाइल अगले रीड्रिथ के लिए स्क्रिप्ट फ़ाइल है।


1
बिना शर्त Hपहले रखना प्यारा है।
18

@mikeserv आपके इनपुट के लिए धन्यवाद। मैं लाइन साइकिल रखने में संभावित लाभ देख सकता हूं, लेकिन यह कम काम कैसे है?
डिकटीर

@ अच्छी तरह से, वाक्यविन्यास कुछ शॉर्टकट लेता है :a;$!{N;ba}जैसा कि मैंने ऊपर उल्लेख किया है - जब आप अपरिचित सिस्टम पर regexps चलाने का प्रयास करते हैं तो लंबे समय में मानक रूप का उपयोग करना आसान होता है। लेकिन यह वास्तव में मेरा क्या मतलब नहीं था: आप एक बंद लूप को लागू करते हैं - आप आसानी से उस के बीच में नहीं आ सकते हैं जब आप चाहते हैं कि आप इसके बजाय बाहर जा सकते हैं - अवांछित डेटा को छांट कर - और चक्र होने दें। यह एक टॉप-डाउन चीज़ की तरह है - जो कुछ भी sedकरता है उसका प्रत्यक्ष परिणाम है जो उसने अभी किया है। हो सकता है कि आप इसे अलग तरह से देखते हों - लेकिन अगर आप इसे आजमाते हैं तो हो सकता है कि आपको स्क्रिप्ट आसान लगे।
mikeserv

11

यह विफल हो जाता है क्योंकि Nकमांड पैटर्न मैच $!(अंतिम पंक्ति नहीं) से पहले आता है और किसी भी काम को करने से पहले सेड करता है:

एन

पैटर्न स्पेस में एक नईलाइन जोड़ें, फिर पैटर्न स्पेस में इनपुट की अगली लाइन जोड़ें। यदि कोई और इनपुट नहीं है तो sed बिना किसी और कमांड को प्रोसेस किए बाहर निकल जाता है

यह आसानी से एकल-लाइन इनपुट के साथ काम करने के लिए तय किया जा सकता है (और वास्तव में किसी भी मामले में अधिक स्पष्ट होने के लिए) केवल पैटर्न के बाद Nऔर bआदेशों को समूहीकृत करके :

sed ':a;$!{N;ba}; [commands...]'

यह निम्नानुसार काम करता है:

  1. :a 'a' नाम का एक लेबल बनाएं
  2. $! यदि अंतिम पंक्ति नहीं है, तो
  3. Nअगली पंक्ति को पैटर्न स्पेस में जोड़ें (या अगली पंक्ति नहीं होने पर छोड़ दें) और baशाखा (लेबल पर जाएँ) 'a'

दुर्भाग्य से, यह पोर्टेबल नहीं है (जैसा कि यह GNU एक्सटेंशन पर निर्भर करता है), लेकिन निम्न विकल्प (@mikeserv द्वारा सुझाया गया) पोर्टेबल है:

sed 'H;1h;$!d;x; [commands...]'

मैंने इसे यहां पोस्ट किया क्योंकि मुझे जानकारी कहीं और नहीं मिली और मैं इसे उपलब्ध कराना चाहता था ताकि अन्य लोग व्यापक रूप से परेशानी से बच सकें :a;N;$!ba;
डिकट्री

पोस्ट करने का शुक्रिया! याद रखें कि अपने स्वयं के उत्तर को स्वीकार करना भी ठीक है। आपको सिस्टम को करने से पहले बस थोड़ी देर प्रतीक्षा करने की आवश्यकता है।
टेराडो ter
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.