एक स्क्रिप्ट में sed का उपयोग करते समय मुझे किन वर्णों से बचने की आवश्यकता है?


248

निम्नलिखित स्क्रिप्ट लें:

#!/bin/sh
sed 's/(127\.0\.1\.1)\s/\1/' [some file]

अगर मैं इसे sh( dashयहां) चलाने की कोशिश करता हूं , तो यह कोष्ठक के कारण विफल हो जाएगा, जिससे बचने की जरूरत है। लेकिन मैं नहीं है बैकस्लैश खुद को बचने के लिए (ओकटेट के बीच, या में की जरूरत है \sया \1)। यहाँ क्या नियम है? जब मुझे उपयोग करने की आवश्यकता हो {...}या इसके बारे में क्या हो [...]? वहाँ एक सूची है कि मैं क्या करूँ और भागने की आवश्यकता नहीं है?


1
यहाँ SED के साथ उपयोग के लिए पथ परिवर्तित करने के लिए एक बश फ़ंक्शन है:function sedPath { path=$((echo $1|sed -r 's/([\$\.\*\/\[\\^])/\\\1/g'|sed 's/[]]/\[]]/g')>&1) } #Escape path for use with sed
user2428118


ड्यूरा लेक्स, सेड सेड
निमो

जवाबों:


281

यहाँ व्याख्या के दो स्तर हैं: शेल, और सेड।

शेल में, सिंगल कोट्स के बीच सब कुछ शाब्दिक रूप से व्याख्या किया जाता है, केवल सिंगल कोट्स के अलावा। आप प्रभावी रूप से एकल उद्धरणों के बीच एक एकल उद्धरण लिख सकते हैं '\''(करीबी एकल उद्धरण, एक शाब्दिक एकल उद्धरण, खुला एकल उद्धरण)।

सैड बुनियादी नियमित अभिव्यक्ति का उपयोग करता है । BRE में, उन्हें शाब्दिक रूप से व्यवहार $.*[\^करने के लिए, वर्ण सेट के अंदर ( […]) छोड़कर, एक बैकस्लैश द्वारा वर्णों को उद्धृत करने की आवश्यकता होती है । पत्र, अंक और (){}+?|उद्धृत नहीं किया जाना चाहिए (आप कुछ कार्यान्वयन में इनमें से कुछ को उद्धृत करने के साथ दूर हो सकते हैं)। दृश्यों \(, \), \n, और कुछ कार्यान्वयन में \{, \}, \+, \?, \|और अन्य बैकस्लैश + अक्षर या अंक विशेष अर्थ है। आप $^कुछ कार्यान्वयनों में कुछ पदों पर उद्धृत नहीं कर सकते हैं ।

इसके अलावा, यदि आपको /ब्रैकेट अभिव्यक्ति के बाहर रेगेक्स में प्रदर्शित होना है , तो आपको बैकस्लैश की आवश्यकता होगी । आप एक वैकल्पिक चरित्र को परिसीमन के रूप में लिखकर चुन सकते हैं, जैसे, s~/dir~/replacement~या \~/dir~p; यदि आप इसे BRE में शामिल करना चाहते हैं, तो आपको सीमांकक से पहले बैकस्लैश की आवश्यकता होगी। यदि आप एक ऐसे चरित्र का चयन करते हैं जिसका BRE में एक विशेष अर्थ है और आप इसे शाब्दिक रूप से शामिल करना चाहते हैं, तो आपको तीन बैकस्लैश की आवश्यकता होगी; मैं इसकी अनुशंसा नहीं करता, क्योंकि यह कुछ कार्यान्वयनों में अलग तरह से व्यवहार कर सकता है।

संक्षेप में, इसके लिए sed 's/…/…/':

  • एकल उद्धरणों के बीच रेगेक्स लिखें।
  • '\''रेगेक्स में एक एकल उद्धरण के साथ समाप्त करने के लिए उपयोग करें ।
  • पहले $.*/[\]^और केवल उन पात्रों (लेकिन ब्रैकेट अभिव्यक्तियों के अंदर नहीं) में एक बैकस्लैश डालें । (तकनीकी तौर पर आपको इससे पहले कोई बैकस्लैश नहीं डालना चाहिए ]लेकिन मुझे ऐसे कार्यान्वयन के बारे में नहीं पता है जो व्यवहार करता है ]और \]अलग - अलग कोष्ठक अभिव्यक्तियों के बाहर है।)
  • ब्रैकेट अभिव्यक्ति के अंदर, -शाब्दिक रूप से व्यवहार किए जाने के लिए, सुनिश्चित करें कि यह पहले या अंतिम ( [abc-]या [-abc]नहीं [a-bc]) है।
  • ब्रैकेट अभिव्यक्ति के अंदर, ^शाब्दिक रूप से व्यवहार किए जाने के लिए, सुनिश्चित करें कि यह पहले नहीं है (उपयोग करें [abc^], नहीं [^abc])।
  • शामिल करने के लिए ]एक ब्रैकेट अभिव्यक्ति के अनुरूप पात्रों की सूची में, यह पहली चरित्र (या पहले के बाद बनाना ^: एक नकार सेट के लिए) []abc]या [^]abc](नहीं [abc]]है और न ही[abc\]] )।

प्रतिस्थापन पाठ में:

  • &और \उन्हें एक बैकस्लैश द्वारा उद्धृत करने से पहले उद्धृत करने की आवश्यकता है, जैसा कि सीमांकक (आमतौर पर /) और newlines।
  • \अंक के बाद एक विशेष अर्थ होता है। \पत्र के बाद कुछ कार्यान्वयन में एक विशेष अर्थ (विशेष वर्ण) होता है, और \इसके बाद कुछ अन्य चरित्र साधन \cया cकार्यान्वयन पर निर्भर करता है।
  • तर्क ( sed 's/…/…/') के चारों ओर एकल उद्धरणों के साथ , '\''प्रतिस्थापन पाठ में एकल उद्धरण लगाने के लिए उपयोग करें।

यदि रेगेक्स या प्रतिस्थापन पाठ शेल चर से आता है, तो याद रखें

  • रेगेक्स एक BRE है, न कि शाब्दिक तार।
  • रेगेक्स में, एक नई पंक्ति को व्यक्त करने की आवश्यकता होती है \n(जो तब तक मेल नहीं खाएगी जब तक कि आपके पास sedपैटर्न स्थान पर नई पंक्ति वर्ण जोड़ने का कोई अन्य कोड न हो )। लेकिन ध्यान दें कि यह कुछ sedकार्यान्वयन के साथ ब्रैकेट एक्सप्रेशन के अंदर काम नहीं करेगा ।
  • प्रतिस्थापन पाठ में &, \और newlines को उद्धृत करने की आवश्यकता है।
  • परिसीमन को उद्धृत किया जाना चाहिए (लेकिन ब्रैकेट के भावों के अंदर नहीं)।
  • प्रक्षेप के लिए दोहरे उद्धरण चिह्नों का उपयोग करें sed -e "s/$BRE/$REPL/":।

वास्तविक वाइल्डकार्ड वर्ण (*) से बचकर आप डबल बैकस्लैश ( \\*) का उपयोग कर सकते हैं । उदाहरण:echo "***NEW***" | sed /\\*\\*\\*NEW\\*\\*\\*/s/^/#/
खतरे

43

शेल में इंटरपोलिंग और भागने के कारण आप जो समस्या अनुभव कर रहे हैं - यह इसलिए है क्योंकि आप सीड -rया --regexp-extendedविकल्प को पास किए बिना विस्तारित रेगुलर एक्सप्रेशन सिंटैक्स का उपयोग करने का प्रयास कर रहे हैं ।

से अपनी sed लाइन बदलें

sed 's/(127\.0\.1\.1)\s/\1/' [some file]

सेवा

sed -r 's/(127\.0\.1\.1)\s/\1/' [some file]

और यह काम करेगा क्योंकि मेरा मानना ​​है कि आप इरादा रखते हैं।

डिफ़ॉल्ट सेड का उपयोग बुनियादी नियमित अभिव्यक्ति (grep शैली के बारे में सोचें) का उपयोग करता है, जिसके लिए निम्नलिखित वाक्यविन्यास की आवश्यकता होगी:

sed 's/\(127\.0\.1\.1\)[ \t]/\1/' [some file]

मुझे यह समस्या फिर से हुई, और पिछली बार हल किए गए समाधान को खोजने के लिए नीचे स्क्रॉल करना भूल गया। एक बार फिर धन्यवाद।
isaaclw

बहुत बहुत धन्यवाद। -rएक विकल्प के रूप में जोड़ना मेरे मामले में आवश्यक था।
HelloGoodbye

15

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

इसलिए यदि आप s/\(127\.0\.1\.1\)\s/\1/इसके चारों ओर सिंगल कोट्स देखना चाहते हैं और शेल कोष्ठक या बैकस्लैश को स्पर्श नहीं करेगा। यदि आपको शेल चर को प्रक्षेपित करने की आवश्यकता है, तो केवल उस भाग को दोहरे उद्धरण चिह्नों में रखें। उदाहरण के लिए

sed 's/\(127\.0\.1\.1\)/'"$ip"'/'

यह आपको यह याद रखने की परेशानी से बचाएगा कि कौन से शेल मेटाचैकर डबल कोट से बच नहीं रहे हैं।


मैं चाहता हूँ sedदेखने के लिए s/(127\.0\.1\.1)/..., लेकिन डाल कि एक खोल स्क्रिप्ट में के रूप में काम नहीं करता है। क्या आप खोल के बारे में कह रहे हैं कि कोष्ठक को छूना गलत नहीं है। मैंने अपने प्रश्न को विस्तार से संपादित किया है।
detly

3
शेल कोष्ठकों को स्पर्श नहीं कर रहा है। आपको बैकस्लैस की आवश्यकता है क्योंकि सिड को उन्हें देखने की आवश्यकता है। sed 's/(127\.0\.1\.1)/IP \1/'विफल रहता है क्योंकि एसईडी देखना पसंद करते हैं \(और \)समूह वाक्य रचना, नहीं करने के लिए (और )
काइल जोन्स

facepalm यह मैन पेज में नहीं है, लेकिन यह मुझे मिले कुछ ऑनलाइन मैनुअल में है। क्या यह regex के लिए सामान्य है, क्योंकि मुझे इसे regex पुस्तकालयों में उपयोग नहीं करना पड़ा है (जैसे, Python)?
detly

3
पारंपरिक यूनिक्स कमांड के लिए, मूल नियमित अभिव्यक्ति और विस्तारित नियमित अभिव्यक्ति हैं। विवरण । sed बुनियादी नियमित अभिव्यक्तियों का उपयोग करता है, इसलिए समूह सिंटैक्स के लिए बैकस्लैश की आवश्यकता होती है। पर्ल और पायथन नियमित रूप से विस्तारित भावों से भी आगे निकल गए। जब मैं चारों ओर झाँक रहा था तो मुझे एक अत्यंत ज्ञानवर्धक चार्ट मिला, जो बताता है कि जब हम "नियमित अभिव्यक्ति" कहते हैं, तो हम एक भ्रमित ब्राम्बल को आकर्षित करते हैं।
काइल जोन्स

1
मैं यह भी जोड़ना चाहूंगा कि एकल उद्धरणों के अंदर उपयोग नहीं किया जा सकने वाला एकमात्र वर्ण एक एकल उद्धरण है।
enzotib
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.