एक ही बार में कई पैटर्न को सेड के साथ कैसे बदलें?


231

मान लीजिए कि मेरे पास 'abbc' स्ट्रिंग है और मैं प्रतिस्थापित करना चाहता हूं:

  • ab -> ई.पू.
  • बीसी -> एबी

अगर मैं दो की कोशिश करता हूं तो परिणाम वही होता है जो मैं नहीं चाहता:

echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab

तो नीचे की तरह बदलने के लिए मैं किस सेड कमांड का उपयोग कर सकता हूं

echo abbc | sed SED_COMMAND
bcab

संपादित करें : वास्तव में पाठ में 2 से अधिक पैटर्न हो सकते हैं और मुझे नहीं पता कि मुझे कितने प्रतिस्थापन की आवश्यकता होगी। चूँकि एक उत्तर था कि sedयह एक धारा संपादक है और इसके स्थान पर लालच है, मुझे लगता है कि मुझे इसके लिए कुछ स्क्रिप्ट भाषा का उपयोग करने की आवश्यकता होगी।


क्या आपको एक ही पंक्ति में कई प्रतिस्थापन करने की आवश्यकता है? यदि gउन दोनों s///आदेशों से केवल झंडा नहीं गिराया गया और वह काम करेगा।
इटन रिस्नर

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

सॉरी @EtanReisner i ने गलत समझा, awser हां है। पाठ में कई प्रतिस्थापन हो सकते हैं।
1

जवाबों:


342

शायद कुछ इस तरह:

sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'

~एक चरित्र के साथ बदलें जो आपको पता है कि स्ट्रिंग में नहीं होगा।


9
जीएनयू हैंडल nuls sed है, तो आप उपयोग कर सकते हैं \x0के लिए ~~
7

3
है gआवश्यक है और यह क्या करता है?
ली

12
@Lee gवैश्विक के लिए है - यह प्रत्येक पंक्ति में पैटर्न के सभी उदाहरणों को प्रतिस्थापित करता है, बजाय पहले के (जो कि डिफ़ॉल्ट व्यवहार है)।
n

1
ओगा के उत्तर की भिन्नता के लिए कृपया मेरा उत्तर stackoverflow.com/a/41273117/539149 देखें जो एक साथ कई संयोजनों को बदल सकता है।
ज़ैक मॉरिस

3
आपको पता है कि स्ट्रिंग में नहीं होगा उत्पादन कोड के लिए, इनपुट के बारे में कभी भी कोई धारणा न बनाएं। परीक्षणों के लिए, ठीक है, परीक्षण वास्तव में कभी सही साबित नहीं होते हैं, लेकिन एक परीक्षण के लिए एक अच्छा विचार है: इनपुट के रूप में स्क्रिप्ट का उपयोग करें।
हैगेलो

33

मैं हमेशा "-ई" के साथ कई बयानों का उपयोग करता हूं

$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sql

यह सभी और से पहले '\ n' को जोड़ देगा, ग्रुप बाय, यूनिअन और FROM's, जबकि 'और' का अर्थ है मिलान स्ट्रिंग और '\ n' का अर्थ है कि आप मिलान किए गए स्ट्रिंग को '\ n' से पहले बदलना चाहते हैं। '


14

यहाँ ओगा के उत्तर पर एक भिन्नता है जो कई खोज के लिए काम करता है और जोड़े को बदले बिना यह जांचने के लिए कि मूल्यों का पुन: उपयोग कैसे किया जा सकता है:

sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt

यहाँ एक उदाहरण है:

इससे पहले:

some text AB some more text "BC" and more text.

उपरांत:

some text BC some more text "CD" and more text.

ध्यान दें कि \bशब्द सीमाओं को दर्शाता है, जो ________कि खोज में हस्तक्षेप करने से रोकता है (मैं Ubuntu पर GNU sed 4.2.2 का उपयोग कर रहा हूं)। यदि आप एक शब्द सीमा खोज का उपयोग नहीं कर रहे हैं, तो यह तकनीक काम नहीं कर सकती है।

यह भी ध्यान दें कि यह समान परिणाम देता है जो कमांड को समाप्त करने s/________//gऔर जोड़ने के && sed -i 's/________//g' path_to_your_files/*.txtलिए है, लेकिन दो बार पथ निर्दिष्ट करने की आवश्यकता नहीं है।

इस पर एक सामान्य भिन्नता का उपयोग करना होगा \x0या _\x0_इसके स्थान पर ________यदि आप जानते हैं कि आपकी फ़ाइलों में कोई नल दिखाई नहीं देता है, जैसा कि jthill ने सुझाव दिया है


मैं हैगेलो की टिप्पणी से सहमत हूं कि इनपुट में क्या हो सकता है, इसकी धारणा नहीं बनाई गई है। इसलिए, मुझे व्यक्तिगत रूप से लगता है कि यह सबसे विश्वसनीय समाधान है, एक दूसरे के ऊपर पाइपिंग सेड्स से अलग ( sed 's/ab/xy/' | sed 's/cd/ab/' .....)
लेटेबाकून

12

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

echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'


4

यह आपके लिए काम कर सकता है (GNU sed):

sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file

यह एक लुकअप तालिका का उपयोग करता है जिसे होल्ड स्पेस (एचएस) में तैयार किया जाता है और फिर प्रत्येक पंक्ति में जोड़ा जाता है। एक अद्वितीय मार्कर (इस मामले में \n) लाइन की शुरुआत के लिए तैयार है और लाइन की लंबाई भर में खोज को टक्कर देने के लिए एक विधि के रूप में उपयोग किया जाता है। एक बार मार्कर लाइन के अंत तक पहुँच जाता है और प्रक्रिया समाप्त हो जाती है और लुकअप टेबल और मार्करों को छोड़ दिया जाता है।

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

कुछ टिप्पणियों के साथ:

sed -r '
  # initialize hold with :abbc:bcab
  1 {
    x
    s/^/:abbc:bcab/
    x
  }

  G        # append hold to patt (after a \n)

  s/^/\n/  # prepend a \n

  :a

  /\n\n/ {
    P      # print patt up to first \n
    d      # delete patt & start next cycle
  }

  s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/
  ta       # goto a if sub occurred

  s/\n(.)/\1\n/  # move one char past the first \n
  ta       # goto a if sub occurred
'

तालिका इस तरह काम करती है:

   **   **   replacement
:abbc:bcab
 **   **     pattern

3

एकल पैटर्न घटना के लिए एक सरल दृष्टिकोण हो सकता है जिसे आप नीचे के रूप में आज़मा सकते हैं: इको 'एबीसीसी' | sed 's / ab / bc /; s / bc / ab / 2'

मेरा आउटपुट:

 ~# echo 'abbc' | sed 's/ab/bc/;s/bc/ab/2'
 bcab

पैटर्न की कई घटनाओं के लिए:

sed 's/\(ab\)\(bc\)/\2\1/g'

उदाहरण

~# cat try.txt
abbc abbc abbc
bcab abbc bcab
abbc abbc bcab

~# sed 's/\(ab\)\(bc\)/\2\1/g' try.txt
bcab bcab bcab
bcab bcab bcab
bcab bcab bcab

उम्मीद है की यह मदद करेगा !!


2

इसके लिए Tcl में एक बिल्डिन है

$ tclsh
% string map {ab bc bc ab} abbc
bcab

यह वर्तमान स्थिति से शुरू होने वाली स्ट्रिंग तुलना करते हुए एक बार में एक चरित्र को चलाकर काम करता है।

पर्ल में:

perl -E '
    sub string_map {
        my ($str, %map) = @_;
        my $i = 0;
        while ($i < length $str) {
          KEYS:
            for my $key (keys %map) {
                if (substr($str, $i, length $key) eq $key) {
                    substr($str, $i, length $key) = $map{$key};
                    $i += length($map{$key}) - 1;
                    last KEYS;
                }
            }
            $i++;
        }
        return $str;
    }
    say string_map("abbc", "ab"=>"bc", "bc"=>"ab");
'
bcab

0

यहाँ awkओगास पर आधारित हैsed

echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1'
bcab
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.