Grep'i, yalnızca eşleşenleri değil tüm satırları çıkarmaya ikna edin


121

Diyelim ki aşağıdaki dosya var:

$ cat test

test line 1
test line 2
line without the search word
another line without it
test line 3 with two test words
test line 4

Varsayılan olarak, greparama terimini içeren her satırı döndürür:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

--colorParametrenin iletilmesi, grepsatırın arama ifadesiyle eşleşen bölümünü vurgulayacaktır, ancak yine de yalnızca ifadeyi içeren satırları döndürür. grepKaynak dosyadaki her satırı çıktı almanın , eşleşmeleri vurgulamanın bir yolu var mı ?

Bunu başarmak için şu anki kötü hack'im (en azından 10000+ ardışık satırları olmayan ve eşleşmeyen dosyalarda):

$ grep -B 9999 -A 9999 test test

İki komutun ekran görüntüsü

Bunu grepbaşaramazsanız, aynı işlevi sunan başka bir komut satırı aracı var mı? Şaşırdım ackama bunun da bir seçeneği yok gibi görünüyor.


1
Olası çapraz site kopyası: stackoverflow.com/questions/981601/… En üstteki cevap her ikisinde de aynıdır.
Ciro Santilli,

1
-C 9999Yerine kullanabilirsiniz . Ben -A 9999 -B 9999her zaman yaparım:grep -C 9999 pattern file
neo

Yanıtlar:


182
grep --color -E "test|$" yourfile

Burada yaptığımız şey, kalıpla test deseniyle eşleşmektir $, açıkçası $renklendirecek bir şey yoktur, bu nedenle yalnızca test deseni renklenir. -ESadece uzun regex eşleştirme açar.

Kolayca şöyle bir işlev oluşturabilirsiniz:

highlight () { grep --color -E "$1|$" "${@:1}" ; }

14
Bu hilkat garibesi harika!
gvkv

3
Ve bir fonksiyon olarak: highlight () { grep --color -E "$1|$" $2 ; }. Kullanımı:highlight test yourfile
Stefan Lasiewski

2
@StefanLasiewski: "$2"ayrıca alıntı yapılmalıdır.
Dennis Williamson

6
Daha iyi olabilir: highlight () { grep --color -E "$1|$" "$@" }bu, adlarında boşluk bulunan dosyaların ve birden fazla dosyanın bulunmasına olanak tanır .
Mike DeSimone

15
@MikeDeSimone - Ama bu "$1"dosyalarda da olacak . Kullanınhighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down

39
ack --passthru --color string file

Ubuntu ve Debian için ack yerine ack-grep kullanın

ack-grep --passthru --color string file

1
Oh, bu açıkça man sayfasında. Körüm. Thanks
Michael Mrozek

Kepçe için desen açıkça ile belirtilebilir --regexp string; ack / ack-grep eşdeğeri--match string
Rhubbarb

ack --passthruPerl ile taklit etmek için:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon

ack --passthruayrıca akarsu üzerinde çalışıyor! Örneğin,ifconfig | ack --passthru inet
honkaboy

12

Bir başka yolu bunu yapmak için düzgün ve portably ile grep(kabul edilen yanıt olarak münavebe ile iki regexes kullanarak yanı sıra) boş desen (sırasıyla boş dize) üzerinden gerçekleştirilir. Standart uyarınca , her
ikisi de -Eve -Fanahtarlarla aynı derecede iyi çalışması gerekir :

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

ve

-F
    Match using fixed strings.
    [...] A null string shall match every line.

Yani bu sadece koşma meselesi

grep -E -e '' -e 'pattern' infile

ve sırasıyla

grep -F -e '' -e 'string' infile

1
Ya da sadece grep -F -e '' -e 'string'.
Stéphane Chazelas

Bu benim için GNU grep 2.25, busybox grep ve yadigarı toolchest ile çalışıyor.
Stéphane Chazelas

Tamam, benim hatam, seq 3 | grep -F -e '' -e 22.27'de yalnızca 2 çıktı (ve 2.26, ama 2.25 değil, git kafasında değil). Sadece ile -F(olmadan veya -E ile). IOW, sadece 2.26 ve 2.27'de hata var ve sadece -F ile görünüyorlar.
Stéphane Chazelas

Not seq 3 | grep -F -e '' -e '' -e 2 2.27 ile de işe yarıyor gibi
Stéphane Chazelas

1
Bu cevapta verilen yöntem basit, doğru ve oldukça hızlı görünüyor . Dediğiniz gibi , otomatik olarak çalışarak -Fhangi karakterlerin göründüğü konusunda endişelenmenize gerek kalmaz string. Bahsetmek isteyebilirsin --color; Bu cevap sayfada göründüğü için (oylar tarafından bakıldığında), daha çok kişi diğer cevaplardan önce onu okuyabilir.
Eliah Kagan

11

Bu tür şeyler için kullandığım aşağıdaki işlevi var:

highlight () {
    perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

Dahili olarak çirkin gözüküyor, hoş ve kullanımı kolay, şöyle:

cat some_file.txt | highlight some_word

veya, biraz daha gerçek dünyadan bir örnek için:

tail -f console.log | highlight ERROR

Değiştirerek - Sen (ben hiç değilim emin grep ile zor olabilir) istediğiniz şekilde renklerini değiştirebilir 1ve 31ve 43(sonra \e[) farklı değerlere. Kodlar kullanımına olan tüm üzerinde yerde ama burada hızlı bir intro var: Metin, 1 bolds 31kırmızı yapar ve 43sarı bir arka plan verir. 32ya 33da farklı renkler olurdu ve 44ya 45da farklı geçmişlere sahip olurdu: fikri anladınız. Eğer 5eğimli iseniz, (a ile ) yanıp sönmesini bile sağlayabilirsiniz .

Bu herhangi bir özel Perl modülü kullanmaz ve Perl neredeyse her yerdedir, bu yüzden hemen hemen her yerde çalışmasını beklerdim. Grep çözümü çok akıllıca, ancak grep üzerindeki --color düğmesi her yerde kullanılamıyor. Örneğin, bu çözümü bash çalışan bir Solaris kutusunda ve başka çalışan bir ksh ve zsh çalıştıran yerel Mac OS X makinemde denedim. Hepsi iyi çalıştı. grep --colorAncak Solaris çözümü boğdu .

Ayrıca, ack harika ve onu henüz keşfetmemiş olan herkese tavsiye ediyorum, ancak üzerinde çalıştığım birçok sunucudan birkaçına yüklerken bazı sorunlar yaşadım. (Nedenini unuttum: Gerekli olan Perl modülleri ile ilgili olduğunu düşünüyorum.)

Sanmıyorum beri ettik şimdiye Unix kutu üzerinde çalıştı vermedi Perl yüklemiş (embedded tip sistemlerde, Linksys yönlendiricileri hariç ve böyle) Bu hemen hemen evrensel olarak kullanılabilir çözüm olduğunu söyleyebilirim .


3

Grep kullanmak yerine, Daha Az kullanabilirsiniz:

less file

Bunun gibi ara: /pattern Enter

Bu irade:

  1. ilk eşleşen satıra git
  2. oradan başlayarak her satırı çıkar.
  3. tüm eşleşmeleri vurgula

Bir sonraki eşleşen satıra geçmek için: n

Önceki eşleşen satıra geçmek için: N

Vurgulamayı değiştirmek için: Esc u

İsterseniz vurgulama rengini de değiştirebilirsiniz .


2

Deneyebilirsin:

perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

Ancak çok taşınabilir değil ve Perl kurulmuş olsa bile, başka bir modül indirmeniz gerekebilir. Ayrıca sadece arama sözcüğünü değil, tüm satırı renklendirir.


2

ripgrep

Kullanım ripgreponun ile --passthruparametre:

rg --passthru pattern file.txt

En hızlı grepping araçlarından biridir , çünkü sonlu otomatlar, SIMD ve aramaları çok hızlı hale getirmek için agresif değişmez optimizasyonlar kullanan Rust'un regex motorunun üzerine inşa edilmiştir .

--passthru - Hem eşleşen hem de eşleşen olmayan satırları yazdırın.

Benzer bir etki elde etmenin bir başka yolu, deseninizi boş dizeyle eşleşecek şekilde değiştirmektir. Örneğin, kullanarak arama yapıyorsanız, bunun yerine rg fookullanmak rg "^|foo", aranan her dosyadaki her satırı yayar, ancak yalnızca foo oluşumları vurgulanır. Bu bayrak, deseni değiştirmeye gerek kalmadan aynı davranışı sağlar.


1

Bunu GNU grep için yapmanın çok daha kolay bir yolu var ama taşınabilir olduğunu düşünmüyorum (yani, BSD grep):

Bir boruda:

cat <file> | grep --color=always -z <query>

Bir dosyada:

grep --color=always -z <query> <file>

Kredi Cyrus'un buradaki cevabına gidiyor .


1
Bu, (ve Cyrus) düşündüğünüz kadar iyi bir cevap değil. Tüm dosyayı tek bir satır olarak ele alma etkisine sahiptir. Dosyası çok büyükse nedenle, (1), bellek tükeniyor olma ihtimali söz konusu olabilir ve dosya deseni içermiyorsa (2) Hiç , sonra hiçbir şey çıkışı olacaktır. Ve haklısın; evrensel olarak mevcut değil. (Ama yine de, --colordeğil , standart ya da.)
G-Man

Grep'in hangi sürümü desteklenmektedir? Grep 2.5.4'te, -z müsait gözükmüyor ...
Alex

1

Şimdiye kadar verilen cevapların hiçbiri taşınabilir bir çözüm sunmuyor.

İşte taşınabilir 1 Ben kabuk işlevi zaten yayınlanmıştır ile sağlanan standart olmayan araçlarını veya standart olmayan uzantıları gerektirmez yinelenen soru olarak kapalı bir yer perl, ack, ggrep, gsed, bashve seviyor ama sadece POSIX kabuğu ve POSIX zorunlu araçları ihtiyacı sedve printf:

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "$@"
}

Bu şekilde kullanabilirsiniz:

grepc string_to_search [file ...]

Vurgu rengi, sed komut bağımsız değişkeninde bu kodlardan biri kullanılarak ayarlanabilir (burada 32m yeşil renk vardır):

30m black
31m red
33m yellow
34m blue
35m magenta
36m cyan
37m white
7m reverse video

1 Terminaliniz ANSI renkleri kaçış dizilerini desteklediği sürece.


0

Bir sedversiyon, hem çalışır bashve ash.

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "$@"
}

0

OP sordu grepve tavsiye edeceğim şey de bu ; Ancak sedkayıt için bir sorunu çözmek için çok uğraştıktan sonra , işte bununla basit bir çözüm:

sed $'s/main/\E[31m&\E[0m/g' testt.c

veya

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

mainKırmızıyla boyayacak .

  • \E[31m : kırmızı renk başlangıç ​​sırası
  • \E[0m : bitmiş renk işareti
  • & : eşleşen desen
  • /g : bir satırdaki tüm kelimeler, sadece ilk değil
  • $'string' kaçış karakterlerinin yorumlandığı bash dizeleridir

Grep ile ilgili ^olarak $(satır sonu ) yerine (satır başlangıcı) kullanarak da çalışır . Örnek:

egrep "^|main" testt.c

ÖNEMLİ DEĞİL bu deli takma adı göstermek için, açık sözlere bile izin verebilirsiniz:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

bütün iş! :) Alıntıyı kapatmayı unutursanız endişelenmeyin, bash sizi "devam eden bir çizgi karakteri" ile hatırlayacaktır.

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.