लाइन पर एन वर्णों के लिए grep संदर्भ सीमित करें


31

मुझे कुछ JSON फ़ाइलों के माध्यम से grep करना है जिसमें लाइन की लंबाई कुछ हजार वर्णों से अधिक है। मैं मैच के बाएं और दाएं N वर्णों के संदर्भ को प्रदर्शित करने के लिए grep को कैसे सीमित कर सकता हूं? Grep के अलावा कोई भी उपकरण ठीक होगा, इसलिए जब तक वह आम लिनक्स पैकेज में उपलब्ध होगा।

यह काल्पनिक grep स्विच p के लिए उदाहरण आउटपुट होगा :

$ grep -r foo *
hello.txt: Once upon a time a big foo came out of the woods.

$ grep -Ф 10 -r foo *
hello.txt: ime a big foo came of t



3
नकल नहीं। यह is वर्णों के बारे में है, लेकिन आपका सुझाया हुआ विकल्प। लाइनों के बारे में है। (करने के लिए आपका संदर्भ stackoverflow अच्छा है, हालांकि है।)
roaima

जवाबों:


22

GNU के साथ grep:

N=10; grep -roP ".{0,$N}foo.{0,$N}" .

स्पष्टीकरण:

  • -o => केवल वही प्रिंट करें जो आपने मिलान किया है
  • -P => पर्ल शैली के नियमित भावों का उपयोग करें
  • रेगेक्स कहते हैं कि 0 से $Nवर्णों का मिलान करें और उसके fooबाद 0 से $Nवर्णों का।

यदि आपके पास GNU नहीं है grep:

find . -type f -exec \
    perl -nle '
        BEGIN{$N=10}
        print if s/^.*?(.{0,$N}foo.{0,$N}).*?$/$ARGV:$1/
    ' {} \;

स्पष्टीकरण:

चूंकि हम अब grepजीएनयू होने पर भरोसा नहीं कर सकते हैं grep, इसलिए हम findपुनरावर्ती रूप से ( -rजीएनयू की कार्रवाई grep) फ़ाइलों की खोज करने के लिए उपयोग करते हैं । प्रत्येक फ़ाइल के लिए, हम पर्ल स्निपेट निष्पादित करते हैं।

पर्ल स्विच:

  • -n फ़ाइल लाइन लाइन द्वारा पढ़ें
  • -l प्रत्येक पंक्ति के अंत में नई लाइन निकालें और इसे प्रिंट करते समय वापस रखें
  • -e निम्नलिखित स्ट्रिंग को कोड के रूप में समझें

पर्ल स्निपेट अनिवार्य रूप से एक ही काम कर रहा है grep। यह आपके द्वारा $Nइच्छित संदर्भ वर्णों की संख्या के लिए एक चर सेट करके शुरू होता है । इसका BEGIN{}मतलब यह है कि निष्पादन की शुरुआत में केवल एक बार निष्पादित किया जाता है, प्रत्येक फ़ाइल में प्रत्येक पंक्ति के लिए एक बार नहीं।

प्रत्येक लाइन के लिए निष्पादित स्टेटमेंट लाइन को प्रिंट करना है यदि रेगेक्स प्रतिस्थापन काम करता है।

रेगेक्स:

  • किसी भी पुराने बात lazily का मिलान करें 1 लाइन के शुरू में ( ^.*?) के बाद .{0,$N}के रूप में grepमामला है, इसके बाद से fooएक और के द्वारा पीछा किया .{0,$N}और अंत में लाइन के अंत तक lazily किसी भी पुराने बात से मेल ( .*?$)।
  • हम इसका विकल्प देते हैं $ARGV:$1$ARGVएक जादुई चर है जो वर्तमान फ़ाइल का नाम पढ़ा जा रहा है। $1इस मामले में संदर्भ: परेंस का मिलान क्या है।
  • या तो अंत में आलसी मैचों की आवश्यकता होती है, क्योंकि एक लालची मैच के लिए fooअसफल होने से पहले सभी पात्रों को खा जाएगा (चूंकि .{0,$N}शून्य बार मिलान करने की अनुमति है)।

1 यानी, जब तक यह मैच पूरी तरह से विफल नहीं होगा, तब तक कुछ भी मैच न करना पसंद करें। संक्षेप में, संभव के रूप में कुछ वर्णों से मेल खाते हैं।


बहुत बढिया आपको धन्यवाद। यह पूरे आउटपुट को हाइलाइट करने का दोष है, न केवल पाठ के लिए खोजा गया है, लेकिन यह | grep fooअंत तक संलग्न करके काम किया जा सकता है (हालांकि प्रक्रिया में हाइलाइटिंग फ़ाइल नाम को खोना)।
dotancohen

1
@dotancohen मुझे लगता है कि आप उन सभी को नहीं जीत सकते :)
यूसुफ आर।

डब्ल्यू / जीएनयू grepआप पर्यावरण चर के माध्यम से लागू झंडे के आधार पर मैच रंग / आवेदन निर्दिष्ट कर सकते हैं। तो शायद आप उन्हें सब जीत सकते हैं , (कोई वादा नहीं - यह भी सुनिश्चित नहीं है कि यह इस मामले में काम करेगा) लेकिन मैं व्यक्तिगत रूप से प्रासंगिकता को यहां नहीं देखता ... वैसे भी ... खेलते रहें।
mikeserv

अच्छा जवाब। zshउदाहरण के रूप में, एन = 10 पास करने के लिए मैं इसे प्राप्त करने में असमर्थ हूं , बस एक नोट । हालाँकि यह काम करता है अगर मैं export N=10कमांड चलाने से पहले। किसी भी विचार कैसे zsh के साथ काम करने के लिए उदाहरण को समायोजित करने के लिए?
गाबे कोपले

याperl -lne 'print "$ARGV: $_" for /.{0,10}foo.{0,10}/g'
स्टीफन चेज़लस

20

इस एक का उपयोग करने का प्रयास करें:

grep -r -E -o ".{0,10}wantedText.{0,10}" *

-ई बताता है, कि आप विस्तारित रेगेक्स का उपयोग करना चाहते हैं

-ओ बताता है, कि आप केवल मैच प्रिंट करना चाहते हैं

-r grep फ़ोल्डर में परिणाम पुन: खोज रहा है

REGEX:

{0,10} बताता है, कि आप कितने मनमाने अक्षर छापना चाहते हैं

एक मनमाना चरित्र का प्रतिनिधित्व करता है (एक चरित्र ही यहाँ महत्वपूर्ण नहीं था, बस उनकी संख्या)

संपादित करें: ओह, मैं देखता हूं, कि यूसुफ लगभग उसी समाधान की सिफारिश करता है जैसा मैं करता हूं: डी


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

आपका स्वागत है, यूनिक्स समुदाय को बस सहयोग करना चाहिए, यही हम :-)
Eenoku

2
यद्यपि वे समान हैं, स्वीकृत उत्तर मेरे लिए काम नहीं करता था (फिर भी लंबी लाइनों का उत्पादन), लेकिन एक ने ऐसा किया। एन = 10 के साथ चाल एक बैश शेल के साथ काम नहीं करती है।
मीसर्न

में cygwin -E काफी तेजी से है -P
बॉब स्टीन

2

से लिया गया: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/ और https: // stackoverflow। com / एक / 39029954/1150462

सुझाव दिया दृष्टिकोण ".{0,10}<original pattern>.{0,10}"पूरी तरह से अच्छा है सिवाय इसके कि हाइलाइटिंग रंग अक्सर गड़बड़ हो जाता है। मैंने एक समान आउटपुट वाली स्क्रिप्ट बनाई है लेकिन रंग भी संरक्षित है:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 | grep --color=none -oE ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

मान लिया जाए कि स्क्रिप्ट को सहेज लिया गया है grepl, तब grepl pattern file_with_long_linesमिलान लाइनों को प्रदर्शित करना चाहिए लेकिन मिलान स्ट्रिंग के चारों ओर केवल 10 वर्णों के साथ।


0

झंडे के cutसाथ पाइपिंग स्टडआउट -b; आप grep के आउटपुट को केवल 1 बाइट्स पर 400 प्रति पंक्ति के माध्यम से निर्देश दे सकते हैं।

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