Grep içeriğini satırdaki N karakterlerle sınırla


31

Satır uzunluğu birkaç bin karakteri aşan bazı JSON dosyalarını incelemeliyim. Grep'in eşleşmenin solunda ve sağında N karakterine kadar içerik göstermesini nasıl sınırlayabilirim? Grep dışındaki herhangi bir araç, ortak Linux paketlerinde bulunduğu sürece iyi de olur.

Bu, hayali grep anahtarı Ф için örnek çıktı olacaktır :

$ 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
Bir kopya değil. Bu yaklaşık ± karakterdir, ancak önerilen alternatifiniz yaklaşık ± satırdır. ( Stackoverflow'a referansınız olsa iyi.)
roaima

Yanıtlar:


22

GNU ile grep:

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

Açıklama:

  • -o => Yalnızca eşleştiğini yazdır
  • -P => Perl tarzı normal ifadeler kullanın
  • Regex için 0 maç söylüyor $Nizledi karakterlerin foo0 izledi $Nkarakterler.

Eğer GNU'nuz yoksa grep:

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

Açıklama:

Artık güvenebilirsiniz yana grepGNU'yu olmanın grep, biz faydalanmak findyinelemeli dosyaları aramak için ( -rGNU eylem grep). Bulunan her dosya için Perl kod parçasını çalıştırıyoruz.

Perl anahtarları:

  • -n Dosyayı satır satır okuyun
  • -l Her çizginin sonundaki yeni çizgiyi kaldırın ve yazdırırken geri koyun
  • -e Aşağıdaki dizgiye kod olarak bak

Perl pasajı aslında aynı şeyi yapıyor grep. İstediğiniz $Niçerik karakter sayısına bir değişken ayarlayarak başlar . Bunun BEGIN{}anlamı, çalıştırmanın başlangıcında sadece bir defa değil, her dosyadaki her satır için bir defa değil.

Her satır için yürütülen ifade, regex ikamesi işe yarıyorsa satırı yazdırmaktır.

Regex:

  • Herhangi eski şeyi lazily Eşleşme 1 satırın başında ( ^.*?), ardından .{0,$N}olduğu gibi grep, ardından durumunda foobaşka izledi .{0,$N}ve sonunda hattın sonuna kadar tembel herhangi eski şeyi eşleşmesi ( .*?$).
  • Bununla ikame ediyoruz $ARGV:$1. $ARGVokunmakta olan dosyanın adını tutan büyülü bir değişkendir. $1parenler ne eşleşti: bu durumda bağlam.
  • Her iki uçtaki tembel maçlar zorunludur, çünkü açgözlü bir maç maçta foobaşarısız olmadan önce tüm karakterleri yiyecektir (çünkü .{0,$N}sıfır kez eşleşmesine izin verilir).

1 Bu, genel eşleşmenin başarısız olmasına neden olmadıkça hiçbir şey eşleştirmemeyi tercih eder. Kısacası, mümkün olduğunca az karakter eşleştirin.


Çok güzel teşekkür ederim. Bu, yalnızca metin için aranan değil tüm çıktıyı vurgulamanın bir dezavantajına sahiptir, ancak sonuna | grep fookadar ekleyerek de çalışılabilir (ancak işlemdeki vurgulanan dosya adını silerek).
dotancohen

1
@dotancohen Sanırım hepsini kazanamazsınız :)
Joseph R.

GNU grepile çevre değişkenleri üzerinden uygulanan bayraklara göre eşleşme renkleri / uygulamaları belirleyebilirsiniz. böylece belki de her verebilir hepsini kazanmak (- bile emin bu durumda çalışacak değil herhangi bir söz) ama neyse ... oynamaya devam ... şahsen yok burada alaka görüyoruz.
mikeserv

Güzel cevap Sadece bir not, kullanarak zshörnek olarak N = 10 geçirerek çalışmasını alamıyorum. Ancak export N=10komutu çalıştırmadan önce çalışırsam çalışır. Zsh ile çalışmak için örneği nasıl ayarlayacağınıza dair bir fikriniz var mı?
Gabe Kopley 17:15

Veyaperl -lne 'print "$ARGV: $_" for /.{0,10}foo.{0,10}/g'
Stéphane Chazelas

19

Bunu kullanmaya çalışın:

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

-E , genişletilmiş regex kullanmak istediğinizi söyler

-o , yalnızca eşleşmeyi yazdırmak istediğinizi söyler

-r grep klasörde özyinelemeli bir sonuç arıyor

REGEX:

{0,10} , kaç tane rasgele karakter yazdırmak istediğinizi söyler

. keyfi bir karakteri temsil eder (bir karakterin kendisi burada önemli değildi, sadece sayıları)

Düzenleme: Oh, görüyorum ki, Joseph benim yaptığımla neredeyse aynı çözümü öneriyor: D


Teşekkür ederim. Esasen aynı çözüm olsa da, iki kişi bağımsız olarak önerdiğinde, bunun en iyi yöntem olduğuna güven uyandırıcıdır .
dotancohen

Bir şey değil, Unix topluluğu iş birliği yapmalı, işte biz
buyuz

2
Benzer olmalarına rağmen, kabul edilen cevap benim için işe yaramadı (hala uzun çizgiler üretti), ancak bir tanesi yaptı. N = 10 olan numara bash kabuğuyla çalışmıyor.
meesern,

içinde cygwin -E önemli ölçüde daha hızlı daha -P.
Bob Stein

2

Alınan: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/ ve https: // stackoverflow. com / a / 39029954/1150462

Önerilen yaklaşım ".{0,10}<original pattern>.{0,10}", vurgulama renginin genellikle dağınık olması haricinde mükemmeldir. Benzer çıktıya sahip bir komut dosyası oluşturdum ancak renk de korunuyor:

#!/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))}"

Komut dosyasının olduğu gibi kaydedildiğini varsayalım grepl, ardından grepl pattern file_with_long_lineseşleşen satırları görüntülemeli ancak eşleşen dizenin etrafında yalnızca 10 karakter bulunmalıdır.


0

Stdout Boru cutile -bbayrak; grep'in çıktısını, satır başına yalnızca 1 ila 400 bayta bildirebilirsiniz.

grep "foobar" * | cut -b 1-400
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.