Обмежте висновок греппінгу на короткі лінії


8

Я часто використовую grep, щоб знайти файли, які мають певний запис, як це:

grep -R 'MyClassName'

Хороша річ у тому, що він повертає файли, їх вміст і позначає знайдений рядок червоним кольором. Погано в тому, що я також маю величезні файли, де весь текст записується в один великий рядок. Тепер grep виводить занадто багато під час пошуку тексту в цих великих файлах. Чи є спосіб обмежити вихід, наприклад, 5 слів ліворуч і праворуч? А може обмежити вихід на 30 літер зліва і справа?



Скажімо, шаблон, який ви шукаєте, знаходиться на позиції 50, але ви сказали, що хочете лише 30 літер. Що ви хочете робити тоді? Ігнорувати цей рядок або також включати його у вихід, але обрізати його? Що саме ви хочете обмежити - пошук чи самі рядки?
Сергій Колодяжний

1
@Rinzwind Я не зовсім розумію, чого ти хочеш досягти cut, оскільки він розпадається лише за роздільником або за кількістю символів. Хоча коли я знаходжу рядок з MyClassNameним, він може бути де-небудь у рядку, а не завжди на одній позиції. Крім того, може бути зміна символів спереду та ззаду, що порушує можливість поділу на роздільник.
Сократ

1
@SergiyKolodyazhnyy Коли знайдено позитивний рядок з MyClassName, я хочу отримати в результаті ім'я файлу та символи x ліворуч та праворуч. x - будь-яке число, яке я надаю, наприклад 30. Решта вмісту файлу ігнорується. Це потрібно, щоб отримати контекст для відповідних файлів і обмежити перевантаження.
Сократ

1
@Rinzwind Який тип користувацького роздільника ви б запропонували, cutякщо є три файли із наступним входом: oiadfaosuoianavMyClassNameionaernaldfajdі /(/&%%§%/(§(/MyClassName&((/$/$/(§/$&і public class MyClassName { public static void main(String[] args) { } }?
Сократ

Відповіді:


15

grepсама має лише параметри контексту на основі рядків. Альтернатива пропонується цим повідомленням SU :

Вирішення завдання полягає в тому, щоб увімкнути опцію "тільки відповідність", а потім використати потужність RegExp, щоб зібрати трохи більше тексту, ніж ваш текст:

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

Звичайно, якщо ви користуєтеся кольоровим підсвічуванням, ви завжди зможете ще раз простукувати, щоб лише кольором реально відповідати:

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

Як іншу альтернативу, я б запропонував foldтекст, а потім прошив, наприклад:

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

-sОпція зробить foldпоштовх слова на наступний рядок замість розриву між ними.

Або скористайтеся іншим способом розділити введення на рядки, виходячи із структури вашого вводу. (Повідомлення SU, наприклад, стосувалося JSON, тому використання jqтощо для симпатичного друку та grep... або просто використання jqфільтрації самостійно ... було б краще, ніж будь-яка з двох наведених вище альтернатив.)


Цей метод GNU awk може бути швидшим:

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
  • Скажіть awk, щоб розділити записи на шаблон, який нас цікавить ( -v RS=...), і кількість символів у контексті ( -v n=...)
  • Кожен запис після першого запису ( FNR > 1) - це той, де awk знайшов відповідність для шаблону.
  • Таким чином, ми друкуємо nсимволи з попереднього рядка ( p) та nпровідні символи з поточного рядка ( substr($0, 0, n)) разом з відповідним текстом для попереднього рядка (який є prt)
    • ми встановлюємо pі prt після друку, тому значення, яке ми встановлюємо, використовується наступним рядком
    • RT є GNUism, саме тому GNU є специфічним.

Для рекурсивного пошуку можливо:

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}' {} +

2
Гаразд, це працює. Здається, що Regex є правильним підходом, тому дякую за це. Хоча час обробки досить великий. Без Regex, як у моїй вище публікації, це займає 4.912s, а з Regex, як у вашій посаді, це займає 3m39.312s.
Сократ

1
@Socrates побачить, чи кращий метод, який я додав вище, працює краще
muru

1
foldМетод може бути використаний тільки якщо ви впевнені , що шукана рядок не з'являється на кордоні, в іншому випадку було б отримати прихований grep.
Мелебій

1
@muru Дякуємо за вашу пропозицію щодо gawk. На жаль, запропонована команда з findвиведеннями випадкових матеріалів і без імен файлів, коли виконується в моїй системі. Крім того, я недостатньо вільний, awkщоб правильно проаналізувати команду. В даний час Regex в поєднанні з grepрішенням питання може бути не швидким, але надійним. Знову дякую.
Сократ

1
@Socrates Я думаю, що мені вдалося виправити команду awk. Моя ментальна модель помилялася щодо того, який рядок RTта префікс тощо слід використовувати.
muru

1

Використання лише узгодження в поєднанні з деякими іншими параметрами (див. Нижче) може бути дуже близьким до того, що ви шукаєте, без обробки накладних регексів, згаданих в іншій відповіді

grep -RnHo 'MyClassName'
  • n числовий вихід, покажіть номер рядка відповідності
  • H ім'я файлу, покажіть ім’я файлу на початку рядка відповідності
  • o тільки збіги, показуйте лише зрівняну рядок, а не весь рядок

Незважаючи на те, що результат знаходить набагато швидше, інформації немає. Відображається шлях до файлу, відображається номер рядка, але виведення тексту - це лише мій початковий пошук MyClassName. Отже, контекст відсутній.
Сократ

grep -RnHo "MyClassName"і grep -Rno "MyClassName"мають однаковий вихід.
Сократ

Вихід @Socrates не однаковий без Н в одному каталозі
Роберт Рідл

-oПрапор може бути цікавий , якщо регулярний вираз було деяка змінна частина. Для фіксованого рядка марно друкувати його кожного разу. ОП, швидше за все, зацікавлений у найближчому контексті.
Мелебій

1
@ Сократ, правда - контекст відсутній, але я думав, що це суть? Обмежити вихід? Ви можете знову додати контекст, додавши рядки до ( -B 1) або після ( -A 1). Вибачте, що мені не могло бути більше допомоги.
Роберт Рідл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.