ग्नू या बीएसडी सेड में रेगेक्स अल्टरनेशन / या ऑपरेटर (फू | बार)


28

मैं इसे काम करने के लिए प्रतीत नहीं कर सकता। GNU sed प्रलेखन पाइप से बचने के लिए कहता है, लेकिन यह काम नहीं करता है, और न ही भागने के बिना सीधे पाइप का उपयोग करता है। Parens को जोड़ने से कोई फर्क नहीं पड़ता।

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat|dog/Bear/g'
cat
dog
pear
banana
cat
dog

$ echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat\|dog/Bear/g'
cat
dog
pear
banana
cat
dog

जवाबों:


33

डिफ़ॉल्ट रूप से sedPOSIX बेसिक रेगुलर एक्सप्रेशन का उपयोग करता है , जिसमें |अल्टरनेशन ऑपरेटर शामिल नहीं है । sedGNU और FreeBSD सहित, के कई संस्करण , विस्तारित नियमित अभिव्यक्तियों में स्विच करने का समर्थन करते हैं, जिसमें |वैकल्पिक रूप से शामिल हैं । आप यह कैसे करते हैं कि यह भिन्न होता है: GNU sed उपयोग करता है-r , जबकि FreeBSD , NetBSD , OpenBSD , और OS X sed उपयोग -E। अन्य संस्करण ज्यादातर इसका समर्थन नहीं करते हैं। आप उपयोग कर सकते हैं:

echo 'cat dog pear banana cat dog' | sed -E -e 's/cat|dog/Bear/g'

और यह उन BSD प्रणालियों पर और sed -rGNU के साथ काम करेगा ।


GNU के sedलिए पूरी तरह से अनैच्छिक लेकिन काम करने का समर्थन प्रतीत होता है -E, इसलिए यदि आपके पास एक बहु-प्लेटफ़ॉर्म स्क्रिप्ट है जो ऊपर तक ही सीमित है जो कि आपका सबसे अच्छा विकल्प है। चूंकि यह प्रलेखित नहीं है इसलिए आप वास्तव में इस पर भरोसा नहीं कर सकते हैं, हालांकि।

एक टिप्पणी नोट करती है कि बीएसडी संस्करण -rएक अनिर्दिष्ट उर्फ ​​के रूप में भी समर्थन करते हैं। OS X अभी भी नहीं है और पुराने NetBSD और OpenBSD मशीनों की पहुंच मेरे पास भी नहीं है, लेकिन NetBSD 6.1 एक है। मैं जिन वाणिज्यिक यूनियनों तक पहुँच सकता हूँ, वे सार्वभौमिक रूप से नहीं। तो इस बिंदु पर पोर्टेबिलिटी प्रश्न बहुत जटिल हो रहा है, लेकिन सरल उत्तर यह है किawk यदि आपको इसकी आवश्यकता है, तो स्विच करना है, जो हर जगह ईआरई का उपयोग करता है।


जिन तीन बीएसडी का आपने उल्लेख किया है वे सभी-r विकल्प को -EGNU sed के साथ अनुकूलता के पर्याय के रूप में समर्थन करते हैं । ओपनबीएसडी और ओएस एक्स की sed -Eबची हुई पाइप की व्याख्या एक वैकल्पिक पाइप के रूप में होगी, न कि वैकल्पिक ऑपरेटर के रूप में। यहां नेटबीएसडी मैन पेज के लिए एक लिंक काम कर रहा है और यहां ओपनबीएसडी के लिए एक है जो दस साल पुराना नहीं है।
डेमियन


GNU sed, -E gnu.org/software/rew/manual/sed.html#index-_002dE का समर्थन करता है ।
इसहाक

9

ऐसा इसलिए होता है क्योंकि (a|b)एक विस्तारित नियमित अभिव्यक्ति है, न कि एक बुनियादी नियमित अभिव्यक्ति। इससे -Eनिपटने के लिए विकल्प का उपयोग करें ।

echo 'cat
dog
pear
banana
cat
dog'|sed -E 's/cat|dog/Bear/g'

से sedआदमी पेज:

 -E      Interpret regular expressions as extended (modern) regular
         expressions rather than basic regular expressions (BRE's).

ध्यान दें कि -rएक ही चीज़ के लिए एक और ध्वज है, लेकिन -Eअधिक पोर्टेबल है और यहां तक ​​कि पोसिक्स विनिर्देशों के अगले संस्करण में भी होगा।


6

ऐसा करने का पोर्टेबल तरीका - और अधिक कुशल तरीका - पते के साथ है। तुम यह केर सकते हो:

printf %s\\n cat dog pear banana cat dog |
sed -e '/cat/!{/dog/!b' -e '};cBear'

इस तरह से अगर लाइन में स्ट्रिंग कैट नहीं है और स्क्रिप्ट से बाहर स्ट्रिंग डॉग sed b रेक शामिल नहीं है , तो इसकी वर्तमान लाइन को ऑटोप्रीन करता है और अगले चक्र को शुरू करने के लिए अगले में खींचता है। इसलिए यह अगला निर्देश नहीं करता है - जो इस उदाहरण में भालूc को पढ़ने के लिए पूरी रेखा को लटका देता है लेकिन यह कुछ भी कर सकता है।

यह शायद यह भी ध्यान देने योग्य है कि !bउस sedआदेश का पालन ​​करने वाला कोई भी कथन केवल एक पंक्ति पर मेल खा सकता है जिसमें या तो स्ट्रिंग है dogया cat- तो आप बिना लाइन के मिलान के किसी भी खतरे के बिना आगे के परीक्षण कर सकते हैं - जिसका मतलब है कि आप अब नियम लागू कर सकते हैं केवल एक या दूसरे को।

लेकिन यह अगले है। यहाँ उपरोक्त कमांड से आउटपुट है:

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

आप बैकरेफ़रेन्स के साथ लुकअप टेबल को आंशिक रूप से लागू कर सकते हैं।

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ cat dog /;x
};G;s/^\(.*\)\n.* \1 .*/Bear/;P;d'

इस सरल उदाहरण मामले के लिए सेटअप करना बहुत अधिक काम है, लेकिन यह sedलंबे समय में और अधिक लचीली स्क्रिप्ट के लिए बना सकता है।

पहली पंक्ति में मैं ई- xहोल्ड स्पेस और पैटर्न स्पेस को बदलता हूं और फिर उन्हें वापस बदलने से पहले स्ट्रिंग <space>कैट <space>डॉग<space> को होल्ड स्पेस में सम्मिलित करता xहूं।

तब से और हर निम्नलिखित लाइन पर मैं Gएट स्पेस को स्पेस स्पेस के साथ जोड़ देता हूं , फिर यह देखने के लिए जांचें कि क्या लाइन के शुरुआत से लेकर जब तक कि नई लाइन मैं अंत में जोड़े गए सभी वर्ण इसके बाद के स्थानों से घिरे स्ट्रिंग से मेल खाते हैं। यदि हां, तो मैं पूरे लॉट को भालू के साथ बदल देता हूं और यदि कोई नुकसान नहीं हुआ है, क्योंकि मैं अगले Pरिंट केवल पैटर्न स्पेस में पहली बार होने वाली न्यूलाइन तक करता हूं, फिर dसभी इसे हटा दें।

###OUTPUT###
Bear
Bear
pear
banana
Bear
Bear

और जब मैं लचीला बोलता हूं, तो मेरा मतलब है। यहाँ यह बदल रहा है बिल्ली के साथ BrownBear और कुत्ते के साथ BlackBear :

printf %s\\n cat dog pear banana cat dog |
sed '1{x;s/^/ 1cat Brown 2dog Black /;x
};G;s/^\(.*\)\n.* [0-9]\1 \([^ ]*\) .*/\2Bear/;P;d'

###OUTPUT###
BrownBear
BlackBear
pear
banana
BrownBear
BlackBear

आप निश्चित रूप से लुकअप टेबल की सामग्री पर एक महान सौदे का विस्तार कर सकते हैं - मैंने इस विषय पर ग्रेग उबेन के यूनेट ईमेल से विचार उठाया , जब 90 के दशक में, उन्होंने बताया कि कैसे उन्होंने एक एकल sed s///कथन से एक कच्चे कैलकुलेटर का निर्माण किया।


1
भतीजी, +1 आपके पास बॉक्स से बाहर सोचने के लिए एक
कलम है जो

@ 1_CR - मेरा अंतिम संपादन देखें - मेरा विचार नहीं - जो यह कहना नहीं है कि मैं इसकी सराहना नहीं करता और इसे एक प्रशंसा मानता हूं। लेकिन मुझे इसका श्रेय देना पसंद है, जहां इसकी वजह है।
मिकसेर्व

1

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

तुम कह सकते हो : sed -E '/^\/\*!(40103|40101|40111).*\/;$/d'

या इसे अपनी sed फाइल में डालें:

/^\/\*!40103.*\/;$/d
/^\/\*!40101.*\/;$/d
/^\/\*!40111.*\/;$/d

0

यहां एक तकनीक है जो किसी भी कार्यान्वयन के विशिष्ट विकल्पों sed(जैसे -E, -r) का उपयोग नहीं करती है । पैटर्न को एक एकल रेगेक्स के रूप में वर्णित करने के बजाय cat|dog, हम केवल sedदो बार चला सकते हैं :

echo 'cat
dog
pear
banana
cat
dog' | sed 's/cat/Bear/g' | sed 's/dog/Bear/g'

यह वास्तव में एक स्पष्ट समाधान है, लेकिन साझा करने के लायक है। यह स्वाभाविक रूप से दो से अधिक पैटर्न स्ट्रिंग्स के लिए सामान्यीकृत है, हालांकि बहुत लंबी श्रृंखला sedबहुत अच्छी नहीं लग रही है।

मैं अक्सर sed -iफ़ाइलों में परिवर्तन करने के लिए (जो सभी कार्यान्वयन में समान काम करता है) का उपयोग करता है। यहां, पैटर्न स्ट्रिंग्स की एक लंबी सूची को अच्छी तरह से शामिल किया जा सकता है, क्योंकि प्रत्येक अस्थायी परिणाम फ़ाइल में सहेजना है:

for pattern in cat dog owl; do
    sed -i "s/${pattern}/Bear/g" myfile
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.