Переконайте, що grep виводить усі рядки, не лише ті, що мають відповідність


121

Скажіть, у мене є такий файл:

$ 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

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

$ grep test test

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

Передаючи --colorпараметр, grepвін змусить його виділити частину рядка, яка відповідає пошуковому виразу, але він все одно повертає лише рядки, які містять вираз. Чи є спосіб отримати grepвихід до кожного рядка у вихідному файлі, але виділити відповідність?

Мій поточний жахливий хак для цього (принаймні, для файлів, у яких немає 10000+ послідовних рядків без збігів):

$ grep -B 9999 -A 9999 test test

Скріншот двох команд

Якщо цього grepне вдається досягти, чи є інший інструмент командного рядка, який пропонує такий же функціонал? Я посварився ack, але, схоже, це також не має для нього варіантів.


1
Можливий дублікат між сайтами: stackoverflow.com/questions/981601/… Верхня відповідь однакова для обох.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

1
Ви можете використовувати -C 9999замість -A 9999 -B 9999.I завжди робити:grep -C 9999 pattern file
нео

Відповіді:


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

Що ми тут робимо, це відповідність $шаблону та тестовій схемі, очевидно $, не має нічого забарвлювати, тому лише тестовий малюнок набуває колір. -EПросто включається розширеним узгодження регулярних виразів.

Ви можете легко створити з нього функцію так:

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

14
Це дивовижно!
gvkv

3
І як функція: highlight () { grep --color -E "$1|$" $2 ; }. Використання:highlight test yourfile
Стефан Ласєвський

2
@StefanLasiewski: "$2"також слід цитувати.
Денніс Вільямсон

6
Краще може бути: highlight () { grep --color -E "$1|$" "$@" }що дозволяє файлам із пробілами у своїх іменах та кількох файлах.
Майк Десимоне

15
@MikeDeSimone - Але це також буде "$1"у файлах. Використанняhighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down

39
ack --passthru --color string file

для Ubuntu та Debian використовуйте ack-grep замість ack

ack-grep --passthru --color string file

1
О, це цілком очевидно на сторінці людини; Я сліпий. Спасибі
Михайло Мрозек

шаблон для схоплювання може бути визначений прямо з --regexp string; еквівалент ack / ack-grep дорівнює--match string
Rhubbarb

Для імітації за ack --passthruдопомогою perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Лукас Кімон

ack --passthruтакож працює на потоках! Наприклад,ifconfig | ack --passthru inet
honkaboy

12

Інший спосіб зробити це правильно і переносимо з grep(крім використання двох регулярних виразів з чергуванням , як в прийнятому відповіді) здійснюється через нульовий шаблон (і , відповідно , порожній рядок).
Він повинен однаково добре працювати з обома -Eі -Fперемикачами, оскільки, за стандартом :

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

і

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

Тож це просто справа бігу

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

і відповідно

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

1
Або просто grep -F -e '' -e 'string'.
Стефан Шазелас

Він працює для мене з GNU grep 2.25, грейбом для зайнятої скриньки та інструментом для інструментів реліквія.
Стефан Шазелас

Гаразд, погано, seq 3 | grep -F -e '' -e 2виводить лише 2 у 2,27 (і 2,26, але не 2,25, а не в голову git). Тільки з -F(не без або з -Е). IOW, лише 2,26 і 2,27, здається, мають помилку і лише з -F.
Стефан Шазелас

Зауважте, що seq 3 | grep -F -e '' -e '' -e 2 , здається, працює також з 2.27
Стефан Шазелас

1
Метод, наведений у цій відповіді, простий, правильний і здається досить швидким . Як ви кажете , це працює автоматично -F, усуваючи необхідність турбуватися про те, які персонажі з'являються у string. Ви можете згадати --color; оскільки ця відповідь пливе вгору на сторінці (при перегляді голосами), більше людей можуть закінчити її читати перед іншими відповідями.
Елія Каган

11

У мене є така функція, яку я використовую для таких речей:

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

Всередині це виглядає некрасиво, приємно та просто у використанні:

cat some_file.txt | highlight some_word

або, для дещо більш реального прикладу:

tail -f console.log | highlight ERROR

Ви можете змінити кольори на все що завгодно (що може бути важко з Grep - я не впевнений), змінюючи 1і 31і 43(після \e[) з різними значеннями. Ці коди до застосування все більш місці , але ось короткий вступ: 1 жирним шрифтом текст, то 31робить його червоним, і 43дає жовтий фон. 32або 33були б різними кольорами, 44або 45були б різними фонами: ви розумієте. Ви навіть можете змусити його блимати (з а 5), якщо ви так схильні.

Для цього не використовуються спеціальні модулі Perl, і Perl майже всюдисущий, тому я б очікував, що він працює майже де завгодно. Рішення grep дуже розумне, але перемикач --color на grep доступний не скрізь. Наприклад, я просто спробував це рішення на коробці Solaris, що працює з bash, і іншим запущеним ksh, і на моїй локальній машині Mac OS X, що працює zsh. Всі працювали просто чудово. grep --colorОднак Соларіс захлинулася розчином.

Крім того, Ack є приголомшливим, і я рекомендую його всім, хто ще не виявив його, але у мене виникли деякі проблеми з його встановленням на кількох з багатьох серверів, над якими я працюю. (Я забуваю, чому. Я думаю, що це стосується модулів Perl, які це вимагало.)

Оскільки я не думаю, що я ніколи не працював над коробкою Unix, на якій не було встановлено Perl (за винятком систем вбудованого типу, маршрутизаторів Linksys тощо), я б сказав, що це досить універсальне корисне рішення .


3

Замість використання Grep ви можете використовувати Менше:

less file

Шукайте так: /pattern Enter

Це буде:

  1. перейдіть до першого відповідного рядка
  2. виведіть кожен рядок, починаючи звідти
  3. виділити всі відповідники

Щоб перейти до наступного відповідного рядка: n

Щоб перейти до попереднього відповідного рядка: N

Щоб переключити виділення: Esc u

Також ви можете змінити колір виділення, якщо вам подобається.


2

Ви можете спробувати:

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

Однак не дуже портативний, і навіть якщо Perl встановлений, можливо, вам доведеться завантажити інший модуль. Крім того, він забарвить увесь рядок, а не лише пошукове слово.


2

ripgrep

Використовувати ripgrepз його --passthruпараметром:

rg --passthru pattern file.txt

Це один з найшвидших інструментів прихватування , оскільки він побудований на основі регекс- двигуна Руста, який використовує кінцеві автомати, SIMD та агресивні буквальні оптимізації для швидкого пошуку.

--passthru - Друкувати як збігаючі, так і невідповідні лінії.

Ще один спосіб досягти подібного ефекту - це змінити ваш шаблон відповідно до порожнього рядка. Наприклад, якщо ви шукаєте, використовуючи, rg fooто rg "^|foo"замість цього буде випромінюватися кожен рядок у кожному шуканому файлі, але виділяються лише входи foo. Цей прапор забезпечує таку саму поведінку, не потребуючи модифікації шаблону.


1

Існує набагато простіший спосіб зробити це для GNU grep, але я не думаю, що це портативно (тобто BSD grep):

У трубі:

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

У файлі:

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

Кредит йде на відповідь Кіра тут .


1
Це не така відповідь, як ви (та Сайрус) думаєте. Це спричинить трактування всього файлу як єдиного рядка. Таким чином, (1) , якщо файл дуже великий, може бути можливість запуску з пам'яті, і (2) , якщо файл не містить шаблон взагалі , то нічого не буде виводитися. І ти маєш рацію; вона не є загальнодоступною. (Але знову ж таки, --colorне є стандартним .)
G-Man

На якій версії grep це підтримується? На grep 2.5.4, -z здається недоступним ...
Алекс

1

Жодна з наведених відповідей поки що не забезпечує портативне рішення.

Ось портативна 1 функція оболонки я вже писав в закритому як дубльований питання , який не вимагає нестандартних інструментів або нестандартних розширень , забезпечені perl, ack, ggrep, gsed, bashі любить , але потрібна тільки оболонка POSIX і POSIX обов'язкові утиліти sedі printf:

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

Ви можете використовувати його таким чином:

grepc string_to_search [file ...]

Колір підсвічування можна відрегулювати за допомогою одного з цих кодів у аргументі команди sed (тут зелений 32м):

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

1 До тих пір, поки ваш термінал підтримує послідовність виведення кольорів ANSI.


0

sedВерсія, працює на обох bashі 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

ОП просив grep, і саме це Я РЕКОМЕНДУЮ ; але, намагаючись вирішити проблему sed, для запису, ось просте рішення з ним:

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

або

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

Пофарбуємо mainв червоний колір.

  • \E[31m : послідовність запуску червоного кольору
  • \E[0m : закінчена кольорова позначка
  • & : відповідна картина
  • /g : усі слова в рядку, не тільки перше
  • $'string' це інтерпретація рядків з уникнутими символами

Щодо grep , він також працює, використовуючи ^(початок рядка), а не $(кінець рядка). Приклад:

egrep "^|main" testt.c

І просто щоб показати цьому божевільному псевдоніму, що Я НЕ РЕКОМЕНДУЮ , ви навіть можете дозволити відкритим цитатам:

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

всі працюють! :) Не хвилюйтесь, якщо ви забудете закрити цитату, Баш запам'ятає вас з "продовжувальним символом рядка".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.