Batasi keluaran grep untuk garis pendek

8

Saya sering menggunakan grep untuk menemukan file yang memiliki entri tertentu seperti ini:

grep -R 'MyClassName'

Hal baiknya adalah ia mengembalikan file, isinya, dan menandai string yang ditemukan berwarna merah. Yang buruk adalah bahwa saya juga memiliki file besar di mana seluruh teks ditulis dalam satu baris tunggal besar. Sekarang grep output terlalu banyak ketika menemukan teks di dalam file-file besar itu. Apakah ada cara untuk membatasi output misalnya 5 kata ke kiri dan ke kanan? Atau mungkin membatasi output hingga 30 huruf ke kiri dan ke kanan?

Socrates
sumber
3
Pipa hasil Anda melaluicut
Rinzwind
Jadi, katakanlah pola yang Anda cari ada di posisi 50, tetapi Anda mengatakan Anda hanya ingin 30 huruf. Apa yang ingin Anda lakukan? Abaikan garis itu atau sertakan juga ke dalam output tetapi potong saja? Apa sebenarnya yang ingin Anda batasi - pencarian atau garis itu sendiri?
Sergiy Kolodyazhnyy
1
@Rinzwind Saya tidak begitu mengerti apa yang ingin Anda capai cut, karena hanya dibagi oleh pembatas atau dengan jumlah karakter. Padahal ketika saya menemukan garis MyClassNamedengannya mungkin ada di mana saja di baris tersebut dan tidak selalu pada posisi yang sama. Selain itu, mungkin ada variasi karakter di bagian depan dan belakang, yang mematahkan kemungkinan untuk dipisah oleh pembatas.
Socrates
1
@SergiyKolodyazhnyy Ketika baris positif dengan MyClassNametelah ditemukan, saya ingin mendapatkan sebagai hasilnya nama file dan karakter x ke kiri dan ke kanan. x adalah nomor apa pun yang saya berikan, misalnya 30. Sisa dari isi file akan diabaikan. Ini untuk mendapatkan konteks ke file yang cocok dan membatasi kelebihan.
Socrates
1
@Rinzwind Jenis pembatas khusus yang akan Anda sarankan cutjika ada tiga file dengan input berikut: oiadfaosuoianavMyClassNameionaernaldfajddan /(/&%%§%/(§(/MyClassName&((/$/$/(§/$&dan public class MyClassName { public static void main(String[] args) { } }?
Socrates

Jawaban:

15

grepitu sendiri hanya memiliki opsi untuk konteks berdasarkan garis. Alternatif disarankan oleh posting SU ini :

Solusinya adalah untuk mengaktifkan opsi 'hanya-cocok' dan kemudian menggunakan kekuatan RegExp untuk mendapatkan sedikit lebih banyak daripada teks Anda:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

Tentu saja, jika Anda menggunakan penyorotan warna, Anda selalu dapat grep lagi untuk hanya mewarnai kecocokan nyata:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

Sebagai alternatif lain, saya menyarankan foldteks dan kemudian mengambilnya, misalnya:

fold -sw 80 input.txt | grep ...

The -spilihan akan membuat folddorongan kata-kata untuk baris berikutnya bukannya melanggar di antara.

Atau gunakan cara lain untuk membagi input dalam garis berdasarkan pada struktur input Anda. (Posting SU, misalnya, berurusan dengan JSON, jadi menggunakan jqdll untuk mencetak-cantik dan grep... atau hanya menggunakan jquntuk melakukan penyaringan dengan sendirinya ... akan lebih baik daripada salah satu dari dua alternatif yang diberikan di atas.)


Metode awk GNU ini mungkin lebih cepat:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • Katakan awk untuk membagi catatan pada pola yang kami minati ( -v RS=...), dan jumlah karakter dalam konteks ( -v n=...)
  • Setiap catatan setelah catatan pertama ( FNR > 1) adalah satu di mana awk menemukan kecocokan untuk pola.
  • Jadi kami mencetak nkarakter tambahan dari baris sebelumnya ( p) dan nkarakter utama dari baris saat ini ( substr($0, 0, n)), bersama dengan teks yang cocok untuk baris sebelumnya (yaitu prt)
    • kami mengatur pdan prt setelah mencetak, sehingga nilai yang kami atur digunakan oleh baris berikutnya
    • RT adalah GNUism, itu sebabnya ini adalah GNU awk-specific.

Untuk pencarian rekursif, mungkin:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +
muru
sumber
2
Ok, ini berhasil. Sepertinya Regex adalah pendekatan yang valid, jadi terima kasih untuk itu. Waktu pemrosesan cukup besar. Tanpa Regex seperti pada posting saya di atas dibutuhkan 4,912s dan dengan Regex seperti pada posting Anda dibutuhkan 3m39,312s.
Socrates
1
@ Socrates melihat apakah metode awk yang saya tambahkan di atas berkinerja lebih baik
muru
1
The foldmetode dapat digunakan hanya jika Anda yakin bahwa mencari string yang tidak muncul di perbatasan, jika tidak maka akan mendapatkan disembunyikan oleh grep.
Melebius
1
@muru Terima kasih atas saran Anda bersama gawk. Sayangnya, perintah yang disarankan dengan findmenampilkan hal-hal acak dan tanpa nama file, ketika dijalankan pada sistem saya. Selain itu, saya tidak cukup fasih awkuntuk menganalisis perintah dengan benar. Saat ini, Regex dalam kombinasi dengan greppemecahan masalah mungkin tidak cepat, tetapi dapat diandalkan. Sekali lagi terima kasih banyak.
Socrates
1
@Socrates Saya pikir saya berhasil memperbaiki perintah awk. Model mental saya salah tentang baris RTdan awalan, dll. Yang harus digunakan.
muru
1

Menggunakan pencocokan hanya dalam kombinasi dengan beberapa opsi lain (lihat di bawah), mungkin sangat dekat dengan apa yang Anda cari, tanpa memproses overhead regex yang disebutkan dalam jawaban lain

grep -RnHo 'MyClassName'
  • n keluaran numerik, tunjukkan nomor baris dari kecocokan
  • H nama file, tampilkan nama file di awal baris pertandingan
  • o hanya cocok, hanya menampilkan string matematika, bukan seluruh baris
Robert Riedl
sumber
Meskipun benar bahwa hasilnya ditemukan lebih cepat, ada info yang hilang. Jalur file ditampilkan, nomor baris ditampilkan, tetapi output teks hanya pencarian awal saya MyClassName. Karenanya, konteksnya hilang.
Socrates
grep -RnHo "MyClassName"dan grep -Rno "MyClassName"memiliki output yang sama.
Socrates
@Socrates output tidak sama tanpa H di direktori yang sama
Robert Riedl
The -oflag mungkin menarik jika regex memiliki beberapa bagian variabel. Untuk string tetap, percuma untuk mencetaknya setiap kali. OP kemungkinan besar tertarik pada konteks dekat.
Melebius
1
@ Socrates, true - konteks hilang, tapi saya pikir itu intinya? Batasi output? Anda dapat menambahkan konteks lagi dengan menambahkan baris sebelum ( -B 1) atau sesudah ( -A 1). Maaf saya tidak bisa membantu.
Robert Riedl