Grep 0 के साथ लाइन हटाएं, लेकिन 0.2 नहीं?


12

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

0
0
0.2
0
0
0
0

मुझे एक शून्य के साथ सभी लाइनों को हटाने की आवश्यकता है।
मैं उपयोग करने के लिए सोच रहा था grep -v "0", लेकिन यह भी 0.2 युक्त रेखा को हटा देता है। मैंने देखा कि मैं -wविकल्प का उपयोग कर सकता हूं , लेकिन यह भी काम नहीं करता है।

मैं केवल एक 0 वाली सभी लाइनों को कैसे हटा सकता हूं और उन सभी लाइनों को 0 से शुरू कर सकता हूं?



1
@JulienLopez यह उस सवाल का एक ठिकाना नहीं है। यह प्रश्न एक शब्द के मिलान के बारे में है, और इसके साथ उत्तर दिया गया है -w, जो यहां विफल रहता है।
गौरव

आप grepइस कार्य के लिए उपयोग करने के लिए क्यों मजबूर हैं ? और वास्तव में आप एक शून्य से क्या मतलब है ? यह एक XY समस्या की तरह लगता है
रोलैंड इलिग

1
@RolandIllig यह सोने से 1 घंटे पहले था और मैं यह जांचने के लिए 500,000 स्ट्रिंग्स की एक श्रृंखला शुरू करना चाहता था कि क्या वे बिटकॉइन निजी चाबियां थीं और यदि शेष राशि मिलती है। अगली बार मेरे पास यह देखने का समय था कि मैंने कई हजारों तारों को संसाधित किया था और मैं किसी भी गैर-शून्य मूल्यों के लिए पार्स करना चाहता था।
फिलिप किर्कब्राइड

जवाबों:


35
grep -vx 0

से man grep:

-x, --line-regexp
       Select only those matches that exactly match the whole line.
       For a regular expression pattern, this is like parenthesizing
       the pattern and then surrounding it with ^ and $.

-wविफल रहता है क्योंकि पहले 0को 0.02"शब्द" माना जाता है, और इसलिए यह रेखा मेल खाती है। ऐसा इसलिए है क्योंकि यह "गैर-शब्द" चरित्र के बाद है। आप इसे देख सकते हैं यदि आप बिना मूल आदेश को चलाते हैं -v, अर्थात grep -w "0"


आप -Fविकल्प का उपयोग भी कर सकते हैं क्योंकि हम रेगेक्स पैटर्न का उपयोग नहीं कर रहे हैं, बस सादे स्ट्रिंग मिलान
ग्लेन जैकमैन

@glennjackman शायद मैंने इसे पहले पढ़ा है, लेकिन मैं अब इसे ढूंढ नहीं सकता। -F(आश्चर्यजनक रूप से मेरे साथ) दौड़ते समय या थोड़ी धीमी गति से भी ऐसा ही प्रतीत होता है (~ ५-१०%)। इसलिए, मुझे यकीन नहीं है कि फायदा क्या होगा।
स्पार्कहॉक

2
यह संभव है कि RegEx इंजन का उपयोग इतनी बार और इतने व्यापक रूप से किया जाता है कि उन्होंने इसका एक बहुत ही कुशल संस्करण लागू किया है, लेकिन यह कि "सादा खोज" शायद 30 वर्षों के लिए अपग्रेड नहीं हुई है।
नेल्सन

@ श्रावक: grepसंभवतया बिना मेटाकाट्रैक्टर्स वाले रेग्जेस के लिए एक विशेष मामला है, क्योंकि यह एक सामान्य उपयोग-मामला है। यह आश्चर्यजनक है कि fgrepयह धीमा होगा, लेकिन यह आश्चर्य की बात नहीं है कि एक छोटे पैटर्न को संकलित करते समय इस विशेष मामले को नोटिस करने का ओवरहेड नगण्य है बनाम एक बड़ी फ़ाइल को स्कैन करने का समय। (यदि उसे उस तेज़ गति से जाने के लिए एक विशेष मामले की आवश्यकता है, तो एक चरित्र वर्ग के साथ एक पैटर्न बनाम x.*y।)
पीटर कॉर्ड्स

लेकिन यह शायद एक ओवरसिम्प्लीफिकेशन है क्योंकि इनपुट वास्तव में कई छोटी लाइनें हैं (एक विशाल स्ट्रिंग नहीं)। मैं भूल जाता हूं कि क्या एक लाइन विभाजक के रूप में न्यूलाइन के grepअलावा किसी भी चरित्र को पहचानता है \n। यदि नहीं, तो निहित ^और $ अभी भी एक निश्चित-स्ट्रिंग खोज में बदल सकता है strstr(big_buf, "\n0\n")। (या 0\nबफर की शुरुआत में।) लेकिन हम अभी पहले मैच को संभावित रूप से एक बड़े बफर में नहीं खोज रहे हैं, हम कुशलतापूर्वक फ़िल्टर करना चाहते हैं। लेकिन वैसे भी, सिद्धांत रूप में हाँ यह प्रत्येक पंक्ति की शुरुआत में सिर्फ 2-बाइट का एक ज्ञापन है, और आप आशा करेंगे कि fgrep और grep दोनों इसे देखेंगे।
पीटर कॉर्ड्स

28

ग्रेप के साथ:

grep -v "^0$" file

^लाइन की शुरुआत का मतलब है, लाइन $का अंत।


2
यह वही है जो उपयोगकर्ता ने पूछा था: केवल 1 "0" वाली किसी भी रेखा से बचें।
ओलिवियर दुलक

1
मैं उस तरह से दोहरे उद्धरण चिह्नों के अंदर शाब्दिक डॉलर का चिह्न नहीं डालूंगा।
user541686

@ शर्मादार रेगेक्स के साथ इतनी बड़ी समस्या नहीं है, जैसा कि आम तौर पर या तो पिछले चार या अगले एक अभ्यस्त हो सकता है[a-Z0-9]
संपो सरला - codidact.org

14

जबकि grep इसके लिए इस्तेमाल किया जा सकता है (जैसा कि अन्य उत्तर स्पष्ट रूप से दिखाते हैं), चलो एक कदम पीछे लेते हैं और सोचते हैं कि आप वास्तव में क्या चाहते हैं:

  • आपके पास एक फाइल है जिसमें नंबर हैं
  • आप संख्यात्मक मान के आधार पर फ़िल्टरिंग करना चाहते हैं ।

रेगेक्स चरित्र अनुक्रम डेटा की व्याख्या करता है। वे संख्याओं के बारे में नहीं जानते हैं, केवल व्यक्तिगत अंकों (और उसके नियमित संयोजन) के बारे में। हालांकि आपके विशेष मामले में इस सीमा के आसपास एक सरल हैक है, यह अंततः एक आवश्यकता बेमेल है।

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

awkउदाहरण के लिए, संख्यात्मक तुलनाओं के आधार पर फ़िल्टर कर सकते हैं, जैसे:

awk '$1 == 0' your_file

लेकिन यह भी, शून्य से अधिक संख्या वाले सभी लाइनों को प्राप्त करने के लिए:

awk '$1 > 0' your_file

मुझे रेगेक्स बहुत पसंद है, यह एक महान उपकरण है। लेकिन यह एकमात्र उपकरण नहीं है। जैसा कि कहा जाता है, यदि आपके पास grepसब कुछ है , तो सब कुछ एक नियमित भाषा की तरह दिखता है।


3
मैं तहे दिल से इस बात से सहमत हूँ कि awk यहाँ अधिक सुरुचिपूर्ण हो सकता है ... हालाँकि, यह उपयोगकर्ता की अपेक्षा की तुलना में शायद थोड़ा अधिक मेल खाएगा (प्रत्येक संख्यात्मक मान 0 का मूल्यांकन करता है)। यानी, printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'मिलान हो जाएगा: 0, 0.0और -0.0... और यह भी 0 also! सिर्फ "0" नहीं। (जो कभी-कभी जरूरी होता है, कभी-कभी नहीं)। यदि उपयोगकर्ता केवल "0" चाहता है: awk '/^0$/' (या grep '^0$')। इसके अलावा आपको संपादित करना चाहिए: उपयोगकर्ता !को परीक्षण को नकारात्मक करने के लिए जोड़ना होगा, इसलिए यह छुपाता है 0(और अन्य शून्य) और बाकी को प्रदर्शित करता है। अर्थात:awk '!( $0 == 0)'
ओलिवियर दुलक

1
$1 == "0"
@ ऑलिवर

1
@OlivierDulac मैंने स्पष्ट रूप से >इसके बजाय !=(या, समतुल्य रूप से ! (… == …)) का उपयोग किया था ताकि यह उजागर हो सके कि यह एक मनमाना संख्यात्मक तुलना है, न कि केवल समानता। आपकी अन्य टिप्पणी के रूप में, यह पूरी तरह से सच है, लेकिन फिर हम अनिवार्य रूप से स्ट्रिंग तुलना क्षेत्र में वापस आ गए हैं और मौजूदा समाधान grepकाम का उपयोग कर रहे हैं (हालांकि awkपाठ्यक्रम भी काम करता है)।
कोनराड रुडोल्फ

@KonradRudolph उचित अंक :)
ओलिवियर

1
@glennjackman: वास्तव में अच्छी चाल। लेकिन तब ओपी बल्कि टेस्ट करेगा$0=="0"
ओलिवियर डुलैक

5

grepकी -wएक सा एक तरीका है कि यह (सिवाय अक्षर, अंक या अंडरस्कोर कुछ भी) शब्द और गैर शब्द घटकों में मूल स्ट्रिंग अप विभाजन में घुमावदार है। चूँकि इसमें पहले से ही एक वैध शब्द 0मौजूद 0.02है, जिसमें लाइन हटाने के लिए नकारात्मक तर्क दिया गया था।

sedइस सन्दर्भ में प्रयोग करना थोड़ा आसान है, बस मेल खाने वाले पूरे शब्दों को हटा दें

sed '/^0$/d' file

3

लाइनों आप हटाना चाहते हैं जब उसमें केवल एक 0 अगली पंक्ति के बाद आप निम्न आदेश जारी करके उन पंक्तियों का चयन कर सकते हैं:

grep -v "^0$"

यह केवल घटनाओं की प्रिंट होगा 0कि कर रहे हैं एक पंक्ति के अंत में और एक पंक्ति के आरंभ में एक ही समय में। -vविकल्प तो हमारे चयन उलट।


1
यह उत्तर लगभग अर्कादिअस ड्रबस्ज़क के समान है, लेकिन आप -vइसे भूल गए हैं , इसलिए यह काम नहीं करता है।
गौरव

आप सही हे। जब वह अपना उत्तर पोस्ट कर रहा था तो मैं टाइप कर रहा था, इसलिए मैंने नहीं देखा कि यह पहले ही दिया जा चुका है। मैंने उस भाग को -vविकल्प के साथ गलत किया है, धन्यवाद!
राजसी

0
  • \ b - शब्द सीमा

grep -v "\b0\b"

  • लाइन की शुरुआत, आपका पैटर्न और लाइन का अंत

grep -v "^0$"

  • या @Sparhawk ने सुझाया -vx lineregexp

-W काम करता है, लेकिन आपके मामले में 0.2 दो शब्द हैं क्योंकि डॉट चरित्र एक शब्द विभाजक है।


grep -v "\b0\b"वास्तव में यहाँ काम नहीं करता है। आप किस संस्करण का उपयोग करते हैं?
अरकादिस्ज़ डर्बस्क

grep (BSD grep) 2.5.1-FreeBSDgrep (GNU grep) 2.16
macOS

1
GNU रेगेक्स का उपयोग \<और \>शब्द सीमा के रूप में, लेकिन इसका प्रभाव वैसा ही होगा जैसा कि-w
ग्लेन जैकमैन

0

विविधता के लिए एक और जवाब, मान लें कि आपके पास एक पीसीआरई-सक्षम है grep

grep -Pv "^0(?!\.)"

यह उन रेखाओं से मेल खाने के लिए एक नकारात्मक रूपांतर प्रदर्शित करता है, जो एक डॉट के साथ शुरू होते हैं 0और उसके बाद नहीं होते हैं । फिर -vनॉन-मैचिंग लाइनों को डिस्कस करता है। आप यहां कार्रवाई में देख सकते हैं


1
इससे ऐसी लाइनें भी हट जाएंगी 0123, जो ओपी नहीं चाहता है
irurar

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.