जटिल स्ट्रिंग को खोजने और बदलने के लिए sed का उपयोग करना (अधिमानतः रेगेक्स के साथ)


84

मेरे पास निम्नलिखित सामग्री के साथ एक फाइल है:

<username><![CDATA[name]]></username>
<password><![CDATA[password]]></password>
<dbname><![CDATA[name]]></dbname>

और मुझे एक स्क्रिप्ट बनाने की ज़रूरत है जो पहली पंक्ति में "नाम" को "कुछ" में बदल देती है, दूसरी पंक्ति में "पासवर्ड" को "कुछ", और तीसरी पंक्ति में "नाम" को "कुछ" के लिए। मैं फ़ाइल में होने वाली इन घटनाओं के आदेश पर भरोसा नहीं कर सकता, इसलिए मैं बस "नाम" की पहली घटना को "कुछ" और "नाम" की दूसरी घटना को "कुछ-कुछ" के साथ बदल नहीं सकता। मुझे वास्तव में यह सुनिश्चित करने के लिए आस-पास के तारों की खोज करने की आवश्यकता है कि मैं सही चीज़ ढूंढ रहा हूं और प्रतिस्थापित कर रहा हूं।

अब तक मैंने इस कमांड को पहली "नाम" घटना को खोजने और बदलने की कोशिश की है:

sed -i "s/<username><![CDATA[name]]><\/username>/something/g" file.xml

हालाँकि यह काम नहीं कर रहा है इसलिए मैं सोच रहा हूँ कि इनमें से कुछ पात्रों को भागने की ज़रूरत हो सकती है, आदि।

आदर्श रूप से, मैं दो "उपयोगकर्ता नाम" घटित होने और केवल "नाम" को बदलने के लिए रेगेक्स का उपयोग करने में सक्षम होना चाहूंगा। कुछ इस तरह से लेकिन साथ sed:

<username>.+?(name).+?</username>

और "कुछ" के साथ कोष्ठक में सामग्री को बदलें।

क्या यह संभव है?


2
बस ध्यान दें कि किसी भी regexp- आधारित समाधान, जब तक कि बेहद वंचित नहीं किया जाता है, किसी भी समय इनपुट प्रारूप में परिवर्तन होने का जोखिम होगा। एक्सएमएल, एसजीएमएल या व्युत्पन्न (जो मुझे यह दिखता है) से निपटने के लिए रेगेक्स एक खराब विकल्प है।
बजे एक सीवी

मंजूर की! उदाहरण के लिए XQuery का उपयोग करने पर विचार करें: w3schools.com/xquery/default.asp । यह XML सामग्री को पुनर्प्राप्त और हेरफेर करने के लिए W3C मानक है।
लार्जेट जू

जवाबों:


157
sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml

यह है, मुझे लगता है, तुम क्या देख रहे हो।

स्पष्टीकरण:

  • पहले भाग में कोष्ठक समूहों (वास्तव में तार) को परिभाषित करते हैं जिन्हें दूसरे भाग में पुन: उपयोग किया जा सकता है
  • \1, \2दूसरे भाग में आदि पहले भाग में पकड़े गए i-वें समूह के संदर्भ हैं (क्रमांक 1 से शुरू होता है)
  • -Eविस्तारित नियमित अभिव्यक्तियाँ ( +समूहन हेतु आवश्यक ) सक्षम करता है।

20
-E विकल्प के लिए +1
22

4
यह नाम के साथ एक बैकअप फ़ाइल को पीछे छोड़ देता है (original name) + "-E"
सर्ज बोर्स्च

4
OSX पर मुझे 'sed: 1: "s / (<username> +) नाम (+ ...": \ 1 को RE में परिभाषित नहीं किया गया है। मैंने इस प्रश्न का सटीक उदाहरण एक फ़ाइल में पेस्ट किया है। " मैंने उस फ़ाइल पर इस उत्तर से कमांड को चलाया। हो सकता है कि OSX का अलग वाक्यविन्यास हो;
डेवीडब

1
Sed का gnu संस्करण "-E" पैरामीटर का समर्थन करता है, लेकिन आधिकारिक नहीं। इसका उल्लेख मैनपेज में भी नहीं है। यदि आप विस्तारित रेगेक्स का उपयोग करना चाहते हैं, तो आपको इसके बजाय "-r" पैरामीटर का उपयोग करना होगा।
इकेम क्रुएगर

3
@deweydb के अनुसार इस उत्तर के लिए, आप का उपयोग करना चाहिए \(और \)के बजाय (और )
झांग बज़

14
sed -e '/username/s/CDATA\[name\]/CDATA\[something\]/' \
-e '/password/s/CDATA\[password\]/CDATA\[somethingelse\]/' \
-e '/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/' file.txt

/username/इससे पहले कि sस्ट्रिंग 'उपयोगकर्ता नाम' वाले तर्ज पर ही काम करने के लिए sed बताता है।


1
सुरुचिपूर्ण, कुशल और मामले के लिए पूरी तरह से फिट। +1
लार्जेट

6

यदि sedएक कठिन आवश्यकता नहीं है, तो इसके बजाय एक समर्पित उपकरण का बेहतर उपयोग करें।

यदि आपकी फ़ाइल एक्सएमएल वैध है (न कि केवल 3 एक्सएमएल- लुकिंग टैग), तो आप एक्सएमस्टार्टलेट का उपयोग कर सकते हैं :

xml ed -P -O -L \
  -u '//username/text()' -v 'something' \
  -u '//password/text()' -v 'somethingelse' \
  -u '//dbname/text()' -v 'somethingdifferent' file.xml

उपरोक्त उन स्थितियों में भी काम करेगा जो नियमित अभिव्यक्तियों के साथ हल करना मुश्किल होगा:

  • टैग के मूल्यों को उनके मौजूदा मूल्यों को निर्दिष्ट किए बिना बदल सकते हैं।
  • मानों की जगह ले सकते हैं भले ही वे बच गए हों और सीडीएटीए में संलग्न न हों।
  • भले ही टैग में विशेषताएँ हों, मूल्यों को प्रतिस्थापित कर सकते हैं।
  • आसानी से टैग की घटनाओं को बदल सकते हैं, अगर एक ही नाम के साथ कई हैं।
  • इसे संशोधित करके संशोधित XML को प्रारूपित कर सकते हैं।

ऊपर का संक्षिप्त प्रदर्शन:

bash-4.2$ cat file.xml
<sith>
<master>
<username><![CDATA[name]]></username>
</master>
<apprentice>
<username><![CDATA[name]]></username>
<password>password</password>
<dbname foo="bar"><![CDATA[name]]></dbname>
</apprentice>
</sith>

bash-4.2$ xml ed -O -u '//apprentice/username/text()' -v 'something' -u '//password/text()' -v 'somethingelse' -u '//dbname/text()' -v 'somethingdifferent' file.xml
<sith>
  <master>
    <username><![CDATA[name]]></username>
  </master>
  <apprentice>
    <username><![CDATA[something]]></username>
    <password>somethingelse</password>
    <dbname foo="bar"><![CDATA[somethingdifferent]]></dbname>
  </apprentice>
</sith>

3

आपको कमांड \[.*^$/के नियमित अभिव्यक्ति भाग में और प्रतिस्थापन भाग में प्लस newlines को उद्धृत करना होगा । नियमित अभिव्यक्ति एक बुनियादी नियमित अभिव्यक्ति है , और इसके अलावा आपको कमांड के लिए सीमांकक को उद्धृत करने की आवश्यकता है ।s\&/s

बोली लगाने से बचने के लिए आप एक अलग परिसीमन चुन सकते हैं /। आपको इसके बजाय उस चरित्र को उद्धृत करना होगा, लेकिन आमतौर पर परिसीमन को बदलने का मतलब है कि एक को चुनना है जो पाठ को बदलने या बदलने के लिए या तो पाठ में नहीं होता है।

sed -e 's~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~'

आप प्रतिस्थापन पाठ में कुछ भागों को दोहराने से बचने के लिए समूहों का उपयोग कर सकते हैं, और इन भागों पर भिन्नता को समायोजित कर सकते हैं।

sed -e 's~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~'

sed -e 's~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~'

3
$ sed -e '1s/name/something/2' \
      -e '3s/name/somethingdifferent/2' \
      -e 's/password/somethingelse/2' sample.xml

आप बस संख्या "पूर्व" के रूप में पते का उपयोग कर सकते हैं जो लाइन नंबर को इंगित करता है।

इसके अलावा अंत में संख्या sedपहले मैच की जगह दूसरे मैच को बदलने के लिए कहती है।


1

"नाम" शब्द को "कुछ" शब्द से बदलने के लिए, उपयोग करें:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml

यह निर्दिष्ट शब्द की सभी घटनाओं को प्रतिस्थापित करने वाला है।

अब तक सभी मानक उत्पादन के लिए तैयार है, आप उपयोग कर सकते हैं:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml > anotherfile.xml

किसी अन्य फ़ाइल में परिवर्तन सहेजने के लिए।


0
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...

    -r, --regexp-extended
             use extended regular expressions in the script.

इसलिए एक गुण फ़ाइल में मूल्य को बदलने के लिए

sed -i -r 's/MAIL\=(.+)/MAIL\=user@mymail.com/' etc/service.properties 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.