सीड का उपयोग करके दो स्ट्रिंग्स के सभी घटनाओं को सफाई से स्वैप करें


13

मान लीजिए कि मेरे पास एक फाइल है जिसमें StringA और StringB दोनों की कई घटनाएं हैं। मैं StringA की सभी घटनाओं को StringB के साथ बदलना चाहता हूं, और (साथ-साथ) StringB की सभी घटनाओं को StringA के साथ बदलना चाहता हूं।

अभी, मैं कुछ ऐसा कर रहा हूं

cat file.txt | sed 's/StringB/StringC/g' | sed 's/StringA/StringB/g' | sed 's/StringC/StringA/g'

इस दृष्टिकोण के साथ समस्या यह है कि यह मानता है कि स्ट्रिंग स्ट्रिंग फ़ाइल में नहीं होती है। हालांकि यह व्यवहार में कोई समस्या नहीं है, फिर भी यह समाधान गंदा लगता है - अर्थात, यह अधिक यूनिक्स जादू सीखने के अवसर की तरह लगता है। :)

जवाबों:


11

तो StringBऔर StringAएक ही इनपुट लाइन पर प्रकट नहीं कर सकते, तो आप प्रतिस्थापन एक तरह से प्रदर्शन करने के लिए, और अगर वहाँ थे पहले का कोई घटनाओं स्ट्रिंग की खोज का एकमात्र अन्य तरीका कोशिश sed बता सकते हैं।

<file.txt sed -e 's/StringA/StringB/g' -e t -e 's/StringB/StringA/g'

सामान्य स्थिति में, मुझे नहीं लगता कि सेड में एक आसान तरीका है। वैसे, ध्यान दें कि विनिर्देश अस्पष्ट है अगर StringAऔर StringBओवरलैप कर सकते हैं। यहाँ एक पर्ल समाधान है, जो या तो स्ट्रिंग की बाईं घटना को प्रतिस्थापित करता है, और दोहराता है।

<file.txt perl -pe 'BEGIN {%r = ("StringA" => "StringB", "StringB" => "StringA")}
                    s/(StringA|StringB)/$r{$1}/ge'

यदि आप POSIX टूल के साथ रहना चाहते हैं, तो awk जाने का रास्ता है। Awk के पास सामान्य पैराट्राइज्ड रिप्लेसमेंट के लिए एक आदिम नहीं है, इसलिए आपको अपना रोल करने की आवश्यकता है।

<file.txt awk '{
    while (match($0, /StringA|StringB/)) {
        printf "%s", substr($0, 1, RSTART-1);
        $0 = substr($0, RSTART);
        printf "%s", /^StringA/ ? "StringB" : "StringA";
        $0 = substr($0, 1+RLENGTH)
    }
    print
}'

जब मैं पहली कमांड चलाता हूं, तो sed मुझे बताता है sed: can't read s/StringB/StringA/g: No such file or directory। ऐसा लगता -e t PATTERNहै कि अच्छी तरह से समझा नहीं गया है।
गीकोसिटी

1
@Gyscos -eदूसरे sआदेश से पहले एक लापता था । मैंने अपना जवाब तय कर दिया है।
गिल्स एसओ- बुराई को रोकें '

8

अभी, मैं कुछ ऐसा कर रहा हूँ
...............
इस दृष्टिकोण के साथ समस्या यह है कि यह मानता है कि स्ट्रिंग स्ट्रिंग फ़ाइल में नहीं होती है।

मुझे लगता है कि आपका दृष्टिकोण ठीक है, आपको बस एक स्ट्रिंग के बजाय कुछ और का उपयोग करना चाहिए, कुछ ऐसा जो लाइन में नहीं हो सकता है (पैटर्न स्पेस में)। सबसे अच्छा उम्मीदवार \nईवलाइन है।
आम तौर पर, पैटर्न अंतरिक्ष में कोई इनपुट लाइन ताकि चरित्र में शामिल होंगे, की सभी घटनाओं स्वैप करने के लिए THISऔर THATएक फ़ाइल में, आप चला सकते हैं:

sed 's/THIS/\
/g
s/THAT/THIS/g
s/\n/THAT/g' infile

या, यदि आपका sed \nRHS में भी समर्थन करता है:

sed 's/THIS/\n/g;s/THAT/THIS/g;s/\n/THAT/g' infile

1
ये सुन्दर है। मैं थोड़ा रोया। RHS न्यूलाइन्स करने का एक और तरीका है शेल वेरिएबल्स - sedअगर कुछ मैक्रो को पहले से तैयार कर लिया जाए, तो कुछ निश्चित बचों का समर्थन करता है या नहीं। जैसे set /THIS /THAT "$(printf \\n/)"; sed "s/$2/\\$4g;s/$3$2/g;s/\\n$3/g"- थोड़े बेवकूफ यहाँ, बेशक, लेकिन यह कुछ और समय का एहसास कराता है जब कुछ और समय - विशेष रूप से चार वर्गों और इसी तरह के लिए।
mikeserv

वैसे उस आदमी के बारे में कैसे? वहाँ भी एक जवाब है इसके बारे में। क्या यह तब हुआ जब मैंने टिप्पणी की? मैंने हाल ही में संपादित सूची (शायद) पर बात को पॉप अप करते हुए देखा और शीर्ष उत्तर की शीर्ष रेखा थोड़ी दूर थी (यदि आप केवल गैर-एम्बेडेड लिनक्स के बारे में परवाह करते हैं, तो मुझे लगता है) । मैं वहां गिल्स के सुझाव को पसंद करता हूं - जब तक कि आप लंबे समय तक चलने वाले नहीं होते हैं sed, तब तक लगातार कांटा ओवरहेड eकिऊव्वा दुःस्वप्न होता है। एक अलग नोट पर - मैं pasteएक पूरे दिन के लिए खेल रहा हूं । मैंने एक विकल्प पार्सर बनाया - जैसे column। यह सिर्फ इनपुट स्ट्रिंग्स और स्ट्रिंग्स सामान के लिए एक साथ डैश देता है।
मिकसरोव

3

मुझे लगता है कि दो शब्दों को स्वैप करने के लिए "नॉनस" स्ट्रिंग का उपयोग करना पूरी तरह से वैध है। यदि आप अधिक सामान्य समाधान चाहते हैं तो आप कुछ कर सकते हैं:

sed 's/_/__/g; s/you/x_x/g; s/me/you/g; s/x_x/me/g; s/__/_/g' <<<"say you say me"

वह पैदावार

say me say you

ध्यान दें कि x_xयदि आप "x_x" तार होने की जगह से बचने के लिए दो अतिरिक्त प्रतिस्थापन की आवश्यकता है । लेकिन यहां तक ​​कि अभी भी awkमेरे लिए समाधान की तुलना में सरल लगता है ।


ऐसा लगता है कि पूछने वाले ने कहा कि वे पहले से ही कर रहे थे।
रोएमा

1
हां, मैंने पहले ही अनदेखी कर दी थी (संपादन इतिहास देखें) लेकिन मेरा दिया गया समाधान अलग है क्योंकि यह तब भी काम करता है जब मूल स्ट्रिंग (यहां "x_x") मूल स्ट्रिंग में होती है, इसलिए इसका अधिक सामान्य है।
डेविड ओंगारो

स्मार्ट, लेकिन एक पकड़ है। यदि StringA या StringB सम्‍मिलित है _, तो किसी को _स्वयं को समायोजित करने की आवश्यकता होती है (दूसरे वर्ण का चयन करें) या परेशानी वाला स्ट्रिंग ( s/_/__/gपहले से प्रदर्शन करें , बेहतर लगता है)। आपका समाधान, जैसा कि यह है, आँख बंद करके मनमाने ढंग से तार को लागू नहीं किया जा सकता है।
कामिल मैकियोरोव्स्की 16

@KamilMaciorowski मुझे समझ नहीं आ रहा है कि आपका क्या मतलब है? मैं वास्तव में s/_/__/gपहले से आवेदन करता हूं । शायद सिर्फ एक टेस्टकेस दिखाते हैं जो विफल हो जाता है।
डेविड ओंगारो

@KamilMaciorowski आह मुझे लगता है कि मैं अब समझ गया हूं। आप का मतलब है अगर प्रतिस्थापन तार खुद में एक है _, तो कहते हैं कि के y_ouसाथ की जगह me। हाँ यह सच है कि किसी को भी इसके बारे में पता होना चाहिए और y__ouअभिव्यक्ति में लाना चाहिए। एक स्क्रिप्ट जो प्रतिस्थापन को इनपुट मापदंडों के रूप में लेती है, उसे भी ध्यान में रखना होगा।
डेविड ओंगारो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.