यदि यह एक बार ठीक एक वर्ण सम्‍मिलित करता है तो लाइन को कैसे हटाएं


10

मैं एक फाइल से एक लाइन हटाना चाहता हूं जिसमें केवल एक बार एक विशेष चरित्र होता है, अगर यह एक से अधिक बार मौजूद है या मौजूद नहीं है तो लाइन को फाइल में रखें।

उदाहरण के लिए:

DTHGTY
FGTHDC
HYTRHD
HTCCYD
JUTDYC

यहाँ, जिस चरित्र को मैं हटाना चाहता हूँ C, वह यह है कि कमांड लाइनों को हटा दे FGTHDCऔर JUTDYCक्योंकि उनके पास Cएक ही बार है।

मैं इसका उपयोग कैसे कर सकता हूं sedया awk?

जवाबों:


20

में awkआप कुछ भी करने के लिए क्षेत्र विभाजक सेट कर सकते हैं। यदि आप इसे सेट करते हैं C, तो आपके पास +1 के रूप में कई फ़ील्ड +1 होंगे C

इसलिए यदि आप कहते हैं कि awk -F'C' '{print NF}' <<< "C1C2C3"आपको मिलता है 4: CCC3 Cएस में होते हैं , और इसलिए 4 फ़ील्ड।

आप उन पंक्तियों को हटाना चाहते हैं जिनमें Cएक बार ठीक होता है। इसे ध्यान में रखते हुए, आपके मामले में आप उन पंक्तियों को निकालना चाहेंगे जिनमें बिल्कुल दो- Cफ़ील्ड हैं। तो बस उन्हें छोड़ें:

$ awk -F'C' 'NF!=2' file
DTHGTY
HYTRHD
HTCCYD

4
awkक्षेत्र विभाजक का सूक्ष्म उपयोग !
वैलेंटाइन बी

इंटरफ़ेयरिंग, डिफ़ॉल्ट मामले (FS = "") के रूप में यह अग्रणी स्थान ($ 1 = लाइन पर पहला गैर-स्थान) और भी दोहराव को अनदेखा करता है (आपके पास फ़ील्ड 1 और फ़ील्ड 2 को अलग करने के लिए 5 स्थान हो सकते हैं) ... स्थान शायद विशेष रूप से इलाज किया जाता है? (इसे देखने के लिए, कोई भी इसे कर सकता है awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'और इसे कुछ पंक्तियों में फ़ीड कर सकता है , कुछ में कई जासूस हैं, और अन्य लोग अंतरिक्ष के साथ शुरुआत कर रहे हैं)
ओलिवियर


8

sed दृष्टिकोण:

sed -i '/^[^C]*C[^C]*$/d' input

-i विकल्प इन-प्लेस फ़ाइल संशोधन की अनुमति देता है

/^[^C]*C[^C]*$/- उन रेखाओं से मेल खाता है जिनमें Cकेवल एक बार होता है

d - मिलान लाइनों को हटा दें


8

इसे निम्न प्रकार से किया जा सकता है sed:

कोड:

sed '/C.*C/p;/C/d' file1

परिणाम:

DTHGTY
HYTRHD
HTCCYD

कैसे?

  1. के Cमाध्यम से कम से कम दो प्रतियों के साथ किसी भी लाइन को मैच और प्रिंट करें/C.*C/p
  2. एक के साथ किसी भी लाइन को हटाएँ Cके माध्यम से /C/d, इस लाइनों पहले से ही चरण 1 में मुद्रित शामिल
  3. बाकी लाइनों को डिफॉल्ट प्रिंट करें

2
चतुर वैकल्पिक दृष्टिकोण; मुझें यह पसंद है।
वाइल्डकार्ड

6

यह सी की बिल्कुल एक घटना के साथ लाइनों को हटा देता है।

grep -v '^[^C]*C[^C]*$' file

नियमित अभिव्यक्ति [^C]एक वर्ण से मेल खाती है जो C (या newline) नहीं है, और पुनरावृत्ति ऑपरेटर (उर्फ क्लेन स्टार) *पूर्ववर्ती अभिव्यक्ति के शून्य या अधिक दोहराव को निर्दिष्ट करता है।

डिफ़ॉल्ट आउटपुट grep(और अधिकांश अन्य पाठ-उन्मुख उपकरण) मानक आउटपुट के लिए है; एक नई फ़ाइल पर पुनर्निर्देशित करें और हो सकता है कि मूल फ़ाइल के शीर्ष पर इसे स्थानांतरित करें यदि आप यही चाहते हैं। उसी रेगेक्स का उपयोग sed -iइन-प्लेस संपादन के लिए किया जा सकता है :

sed -i '/^[^C]*C[^C]*$/d' file

(कुछ प्लेटफार्मों पर, विशेष रूप से * BSD सहित macOS, -iविकल्प के लिए एक तर्क की आवश्यकता है, जैसे -i ''।)


1
sed -i '/^[^C]*C[^C]*$/d' file- लगता है जैसे यह पहले पोस्ट किया गया था, आपको कैसा लगता है, साहित्यिक चोरी?
रोमनपेरेक्रेस्ट

1
वास्तव में, कुछ दोहराव है। मैंने grepजवाब के साथ शुरुआत की लेकिन यह स्पष्ट रूप से आसानी से sed -iवेरिएंट तक फैल गया। आपका उत्तर नहीं देखा क्योंकि मैं पिछले grepउत्तरों की तलाश कर रहा था ।
ट्रिपलआई

1
यह केवल स्पष्ट रूप से बचने -iके sedबजाय सुरक्षित है और इसके बजाय एक नई फ़ाइल पर रीडायरेक्ट करता है और मूल को उस के साथ प्रतिस्थापित करता है यदि sedउपयोगिता बिना किसी त्रुटि के बाहर निकलती है।
Kusalananda

2
याgrep -vx '[^C]*C[^C]*'
स्टीफन चेज़लस

@ कुसलानंद लेकिन तब आप उपयोग कर सकते हैं grepक्योंकि यह स्पष्ट और अधिक मजबूत है (विशेष रूप से, sedएक कम जानकारीपूर्ण निकास कोड है)।
ट्रिपलआई

4

फ़ाइल के स्क्रिप्टेड संपादन के लिए POSIX उपकरण (मानक से संशोधित सामग्री को प्रिंट करने के बजाय) है ex

printf '%s\n' 'g/^[^C]*C[^C]*$/d' x | ex file.txt

यदि आप सिड के अपने संस्करण का समर्थन करते हैं, तो निश्चित रूप से आप इसका उपयोगsed -i कर सकते हैं , बस इस बात से अवगत रहें कि यदि आप एक स्क्रिप्ट लिख रहे हैं जो विभिन्न प्रकार के सिस्टम पर चलने का इरादा है।


डेविड फ़ॉस्टर ने टिप्पणियों में पूछा:

क्या कोई कारण है कि आप उपयोग कर रहे हैं या printfनहीं echoया कुछ और पसंद कर रहे हैं ex -c COMMAND?

उत्तर: हां।

के लिए printfबनाम echoयह पोर्टेबिलिटी का सवाल है, देखें कि प्रिंट ईको से बेहतर क्यों है? और कमांड के उपयोग के बीच नईलाइन्स को इंटरसेप्ट करना भी आसान है printf

के लिए printf ... | exबनाम ex -c ..., यह त्रुटि से निपटने का एक सवाल है। इस विशिष्ट आदेश के लिए यह कोई फर्क नहीं पड़ता, लेकिन सामान्य तौर पर यह होता है; उदाहरण के लिए, डालने का प्रयास करें

ex -c '%s/this pattern is not in the file/replacement text/g | x' filename

एक स्क्रिप्ट में। निम्नलिखित के साथ विपरीत:

printf '%s\n' '%s/no matching lines/replacement/g' x | ex file

पहला लटकाएगा और इनपुट का इंतजार करेगा; ईओएफ को exकमांड मिलने पर दूसरा बाहर निकल जाएगा , इसलिए स्क्रिप्ट जारी रहेगी। वैकल्पिक वर्कअराउंड हैं, जैसे कि s///e, लेकिन वे पोसिक्स द्वारा निर्दिष्ट नहीं हैं। मैं पोर्टेबल फॉर्म का उपयोग करना पसंद करता हूं, जो ऊपर दिखाया गया है।

के लिए gआदेश, वहाँ चाहिए अंत में एक नई पंक्ति हो, और मैं का उपयोग करना पसंद printfके बजाय एकल उद्धरण में एक नई पंक्ति embedding आदेशों रैप करने के लिए।


1
क्या कोई कारण है कि आप उपयोग कर रहे हैं या printfनहीं echoया कुछ और पसंद कर रहे हैं ex -c COMMAND?
डेविड फ़ॉस्टर

@DavidFoerster, हाँ। मैंने आपको टिप्पणियों में जवाब देना शुरू कर दिया, लेकिन यह लंबा हो गया, इसलिए मैंने इसे उत्तर में जोड़ दिया।
वाइल्डकार्ड

धन्यवाद और +1! मैं printfबनाम के बारे में जानता था echo(हालांकि मैं आमतौर पर पसंद करता हूं echoजब तर्क कठिन-कोडित होता है) लेकिन मैंने exअब तक बड़े पैमाने पर उपयोग नहीं किया है ।
डेविड फ़ॉस्टर

2

यहां पर्ल के उपयोग के कुछ विकल्प दिए गए हैं।

चूँकि आप केवल एक ही पात्र से मेल खाते हैं, आप tr/C//के मिलानों की संख्या लौटाने के लिए (बिना अनुवाद के, अनुवाद के साथ) का उपयोग कर सकते हैं C:

perl -lne 'print if tr/C// != 1' file

आम तौर पर, यदि आप एक बहु-चरित्र स्ट्रिंग या नियमित अभिव्यक्ति से मेल खाना चाहते हैं, तो आप इसका उपयोग कर सकते हैं:

perl -lne 'print if (@m = /C/g) != 1' file

यह /C/gएक सूची में नियमित अभिव्यक्ति के मैचों को असाइन करता है @mऔर उस सूची की लंबाई प्रिंट करता है जब उस सूची की लंबाई नहीं होती है 1

-iस्विच "यथा-स्थान" संपादित करने के लिए जोड़ा जा सकता है।


2
sed -e '
  s/C/&/2;t   # when 2nd C matches skip processing and print
  /C/d        # either one C or no C, so delete on C
'

sed -e '
   /C/!b     # no C, skip processing and print
   /C.*C/!d  # not(at least 2 C) => 1 C => delete
'

perl -lne 's/C/C/g == 1 or print'

ध्यान दें कि यह GNU को मानता है sed, t #...आम तौर पर #...अधिकांश अन्य sedकार्यान्वयनों में कहे जाने वाले लेबल पर शाखा करेगा ।
स्टीफन चेज़लस

यहां तक ​​कि !bGNU sed भी है क्योंकि शाखा को लेबल या उसके बाद एक नई रेखा के अलावा कुछ भी पसंद नहीं है।

हाँ, b, t, :, }(और r file, w file...) उनके पीछे एक आदेश एक ही लाइन पर नहीं हो सकता। आप अलग-अलग -eविकल्पों का भी उपयोग कर सकते हैं ।
स्टीफन चेज़लस

आपका पर्ल विकल्प सही आउटपुट नहीं देता है। मुझे लगता है कि आप gसंशोधक जोड़ना भूल गए ।
टॉम फेनेच

@TomFenech आप सही हैं। मैं उसे ठीक कर रहा हूं। धन्यवाद।

1

किसी के लिए awkविशेष रूप से चाहते हैं, मैं प्रदान करता हूँ

awk '/C[^C]*C/{next}//{print}'

लाइन को छोड़ दें यदि यह पैटर्न से मेल खाता है, तो इसे प्रिंट करें। आपको वास्तव में ज़रूरत नहीं है {print}, आप //प्रिंट का उपयोग कर सकते हैं और डिफ़ॉल्ट कर सकते हैं , लेकिन मुझे लगता है कि यह स्पष्ट है।

मेरा पहला विचार egrep -vएक ही पैटर्न के साथ उपयोग करना था , लेकिन यह वास्तव में सवाल का जवाब नहीं देता है।


1
कुछ भी मिलान के बाद {next}क्या है? बस कहें awk '/pattern/ {next} 1'और पैटर्न से मेल नहीं खाने वाली सभी लाइनें प्रिंट की जाएंगी। या, बेहतर, awk '!/pattern/'सीधे उन लोगों को मुद्रित करने के लिए।
फेडोरक्वि

@fedorqui के बारे में अच्छी बात !/pattern/(जो किसी तरह मेरे दिमाग को खिसका देती है) लेकिन मैं अब तक //{print}एक गूढ़ व्यक्ति की तुलना में आत्म-व्याख्यात्मक था 1। अपने कोड को बनाए रखने के लिए अगले व्यक्ति से कम से कम क्षमता और प्रवाह मान लें, इसे गंभीरता से कम कुशल या प्रभावी नहीं बनाने के अनुरूप है।
nigel222
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.