Yakinkan grep untuk menampilkan semua lini, bukan hanya yang cocok

121

Katakanlah saya memiliki file berikut:

$ 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

Secara default, grepmengembalikan setiap baris yang berisi istilah pencarian:

$ grep test test

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

Melewati --colorparameter ke grepakan membuatnya menyorot bagian dari baris yang cocok dengan ekspresi pencarian, tetapi masih hanya mengembalikan baris yang berisi ekspresi. Apakah ada cara untuk mendapatkan grepoutput setiap baris dalam file sumber, tetapi sorot pertandingan?

Peretasan mengerikan saya saat ini untuk mencapai ini (setidaknya pada file yang tidak memiliki 10.000+ baris berturut-turut tanpa kecocokan) adalah:

$ grep -B 9999 -A 9999 test test

Cuplikan layar dari dua perintah

Jika greptidak bisa melakukan ini, apakah ada alat baris perintah lain yang menawarkan fungsi yang sama? Saya sudah mengutak-atik ack, tetapi tampaknya tidak memiliki pilihan untuk itu juga.

Michael Mrozek
sumber
1
Kemungkinan duplikat lintas situs: stackoverflow.com/questions/981601/… Jawaban atas sama pada keduanya.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Anda dapat menggunakan -C 9999tempat. -A 9999 -B 9999Saya selalu melakukan:grep -C 9999 pattern file
neo

Jawaban:

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

Apa yang kami lakukan di sini adalah mencocokkan dengan $pola dan pola pengujian, jelas $tidak memiliki apa pun untuk diwarnai sehingga hanya pola pengujian yang berwarna. The -Ehanya menyala pencocokan regex diperpanjang.

Anda dapat membuat fungsi dengan mudah seperti ini:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
jacksonh
sumber
14
Itu sangat luar biasa!
gvkv
3
Dan sebagai fungsi: highlight () { grep --color -E "$1|$" $2 ; }. Penggunaan:highlight test yourfile
Stefan Lasiewski
2
@StefanLasiewski: "$2"juga harus dikutip.
Dennis Williamson
6
Lebih baik bisa: highlight () { grep --color -E "$1|$" "$@" }yang memungkinkan file dengan spasi putih dalam nama mereka dan beberapa file.
Mike DeSimone
15
@ MikeDeSimone - Tapi itu juga ada "$1"di file. Gunakanhighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down
40
ack --passthru --color string file

untuk Ubuntu dan Debian, gunakan ack-grep alih-alih ack

ack-grep --passthru --color string file
Dennis Williamson
sumber
1
Oh, itu cukup jelas di halaman manual; Saya buta. Terima kasih
Michael Mrozek
pola untuk grap dapat ditentukan secara eksplisit dengan --regexp string; padanan ack / ack-grep adalah--match string
Rhubbarb
Untuk mensimulasikan ack --passthrudengan perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon
ack --passthrujuga berfungsi di stream! Misalnya,ifconfig | ack --passthru inet
honkaboy
13

Cara lain untuk melakukan ini dengan benar dan mudah dibawa dengan grep(selain menggunakan dua regex dengan pergantian seperti pada jawaban yang diterima) adalah melalui pola nol (dan masing-masing string nol).
Ini harus bekerja sama baiknya dengan keduanya -Edan -Fberalih karena, sesuai standar :

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

dan

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

Jadi itu hanya masalah berlari

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

dan masing-masing

grep -F -e '' -e 'string' infile
don_crissti
sumber
1
Atau adil grep -F -e '' -e 'string'.
Stéphane Chazelas
Ini berfungsi untuk saya dengan GNU grep 2.25, busybox grep dan heirloom toolchest.
Stéphane Chazelas
OK, salah saya, seq 3 | grep -F -e '' -e 2tidak hanya menghasilkan 2 di 2,27 (dan 2,26, tetapi tidak 2,25, dan tidak di git head). Hanya dengan -F(bukan tanpa atau dengan -E). TKI, hanya 2,26 dan 2,27 tampaknya memiliki bug dan hanya dengan -F.
Stéphane Chazelas
Catatan yang seq 3 | grep -F -e '' -e '' -e 2 tampaknya bekerja dengan baik dengan 2.27
Stéphane Chazelas
1
Metode yang diberikan dalam jawaban ini sederhana, benar, dan tampaknya cukup cepat . Seperti yang Anda katakan , ini berfungsi secara otomatis -F, mengurangi kebutuhan untuk khawatir tentang karakter apa yang muncul string. Anda mungkin ingin menyebutkan --color; karena jawaban ini muncul di halaman (bila dilihat oleh suara), lebih banyak orang akhirnya membacanya sebelum jawaban yang lain.
Eliah Kagan
11

Saya memiliki fungsi berikut yang saya gunakan untuk hal-hal seperti:

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

Secara internal terlihat agak jelek, bagus dan mudah digunakan, seperti:

cat some_file.txt | highlight some_word

atau, untuk contoh dunia nyata yang sedikit lebih:

tail -f console.log | highlight ERROR

Anda dapat mengubah warna menjadi apa pun yang Anda suka (yang mungkin sulit dengan grep - Saya tidak yakin) dengan mengubah 1dan 31dan 43(setelah \e[) ke nilai yang berbeda. The kode untuk digunakan adalah semua lebih tempat , tapi di sini adalah intro cepat: 1 bolds teks, 31membuatnya merah, dan 43memberikan latar belakang kuning. 32atau 33akan menjadi warna yang berbeda, dan 44atau 45latar belakang yang berbeda: Anda mendapatkan idenya. Anda bahkan dapat membuatnya berkedip (dengan a 5) jika Anda cenderung.

Ini tidak menggunakan modul Perl khusus, dan Perl hampir di mana-mana, jadi saya berharap itu berfungsi hampir di mana saja. Solusi grep sangat pintar, tetapi tombol --color pada grep tidak tersedia di mana-mana. Sebagai contoh, saya baru saja mencoba solusi ini pada kotak Solaris yang menjalankan bash, dan ksh lain yang sedang berjalan, dan mesin Mac OS X lokal saya menjalankan zsh. Semua bekerja dengan baik. Solaris tersedak grep --colorsolusi, namun.

Ack juga luar biasa, dan saya merekomendasikannya kepada siapa saja yang belum menemukannya, tapi saya punya beberapa masalah menginstalnya pada beberapa dari banyak server yang saya kerjakan. (Saya lupa mengapa: Saya pikir terkait dengan modul Perl yang diperlukan.)

Karena saya tidak berpikir saya pernah bekerja pada kotak Unix yang tidak memiliki Perl diinstal (dengan pengecualian sistem tipe tertanam, router Linksys, dan semacamnya) Saya akan mengatakan ini cukup banyak solusi yang dapat digunakan secara universal .

iconoclast
sumber
3

Alih-alih menggunakan Grep, Anda dapat menggunakan Lebih Sedikit:

less file

Cari seperti ini: /pattern Enter

Ini akan:

  1. gulir ke baris pertama yang cocok
  2. Keluarkan setiap baris mulai dari sana
  3. sorot semua pertandingan

Untuk menggulir ke baris yang cocok berikutnya: n

Untuk menggulir ke baris yang cocok sebelumnya: N

Untuk beralih menyoroti: Esc u

Anda juga dapat mengubah warna sorotan jika diinginkan.

Steven Penny
sumber
2

Anda dapat mencoba:

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

Namun tidak terlalu portabel, dan bahkan jika Perl diinstal, Anda mungkin perlu mengunduh modul lain. Selain itu akan mewarnai seluruh baris, bukan hanya kata pencarian.

gvkv
sumber
2

ripgrep

Gunakan ripgrepdengan --passthruparameternya:

rg --passthru pattern file.txt

Ini adalah salah satu alat grepping tercepat , karena itu dibangun di atas mesin regex Rust yang menggunakan automata terbatas, SIMD dan optimisasi literal agresif untuk membuat pencarian sangat cepat.

--passthru - Cetak baris yang cocok dan yang tidak cocok.

Cara lain untuk mencapai efek serupa adalah dengan memodifikasi pola Anda agar cocok dengan string kosong. Misalnya, jika Anda mencari menggunakan rg foomaka menggunakan rg "^|foo"akan memancarkan setiap baris di setiap file yang dicari, tetapi hanya kejadian foo yang akan disorot. Bendera ini memungkinkan perilaku yang sama tanpa perlu mengubah pola.

kenorb
sumber
1

Ada cara yang jauh lebih mudah untuk melakukan ini untuk GNU grep tetapi saya tidak berpikir itu portabel (yaitu, BSD grep):

Dalam pipa:

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

Pada file:

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

Kredit pergi ke jawaban Cyrus di sini .

Erik Nomitch
sumber
1
Ini bukan jawaban yang baik seperti yang Anda (dan Cyrus) pikirkan. Ini memiliki efek memperlakukan seluruh file sebagai satu baris. Oleh karena itu, (1) jika file sangat besar, mungkin ada kemungkinan kehabisan memori, dan (2) jika file tidak mengandung pola sama sekali , maka tidak ada yang akan dihasilkan. Dan kamu benar; itu tidak tersedia secara universal. (Tapi sekali lagi, --coloritu juga bukan standar .)
G-Man
Versi grep apa yang didukung ini? Pada grep 2.5.4, -z sepertinya tidak tersedia ...
Alex
1

Tidak ada jawaban yang diberikan sejauh ini memberikan solusi portabel .

Berikut ini adalah portable 1 fungsi shell saya sudah diposting secara tertutup sebagai duplikat pertanyaan yang tidak memerlukan alat-alat standar non atau ekstensi non standar disediakan dengan perl, ack, ggrep, gsed, bashdan sejenisnya tetapi hanya membutuhkan shell POSIX dan POSIX utilitas wajib seddan printf:

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

Anda dapat menggunakannya seperti itu:

grepc string_to_search [file ...]

Warna highlight dapat disesuaikan dengan menggunakan salah satu kode ini dalam argumen perintah sed (32m menjadi hijau di sini):

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

1 Selama terminal Anda mendukung urutan pelolosan warna ANSI.

Jlliagre
sumber
0

Sebuah sedversi, bekerja pada kedua bashdan 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" "$@"
}
yurenchen
sumber
0

OP meminta grep, dan itulah yang saya sarankan ; tetapi setelah berusaha keras untuk memecahkan masalah dengan sed, sebagai catatan, berikut adalah solusi sederhana untuk itu:

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

atau

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

Akan dicat mainmerah.

  • \E[31m : urutan mulai warna merah
  • \E[0m : tanda warna jadi
  • & : pola yang cocok
  • /g : semua kata dalam satu baris, bukan hanya yang pertama
  • $'string' adalah string bash dengan karakter yang lolos ditafsirkan

Mengenai grep , ia juga bekerja menggunakan ^(mulai dari baris) bukan $(akhir dari baris). Contoh:

egrep "^|main" testt.c

Dan hanya untuk menunjukkan alias gila ini yang SAYA TIDAK MENYARANKAN , Anda bahkan dapat membiarkan tanda kutip terbuka:

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

semua bekerja! :) Jangan khawatir jika Anda lupa untuk menutup kutipan, bash akan mengingat Anda dengan "karakter garis lanjutan".

Dr Beco
sumber