«Grep», который выделяет вместо фильтра

Мне было интересно, есть ли в общем наборе инструментов Unix программа, такая как grep, которая вместо фильтрации строк, содержащих строку, просто выводит тот же ввод, но выделяет или окрашивает выбранную строку.

Я думал сделать это самостоятельно (должно быть достаточно просто), но, возможно, он уже существует как команда unix.

Я планирую использовать его для мониторинга журналов, поэтому я бы сделал что-то вроде этого:

tail -f logfile.log | highlight "error"

Обычно, когда я отслеживаю журналы, мне нужно найти конкретную строку, но мне также нужно знать, что написано до и после строки, поэтому фильтрации иногда недостаточно.

Что-то подобное существует?

Спасибо

В значительной степени ответил здесь: stackoverflow.com/questions/981601/…
Это выглядит не по теме для меня, так как не запрашивает приложение. Конечно, лучше спросить на unix.stackexchange.com.

Ответы (14)

Это забавный трюк для него с основной grepкомандой. Он заключается в использовании двух фильтров: того, который вы хотите применить, и фиктивного, который соответствует всем линиям, но не выделяет их. Это фиктивное совпадение может быть либо ^(начало строки), либо $(конец строки).

grep "^\|text" --color='always' file

или же

grep -E "^|text" --color='always' file

См. пример:

$ cat a
hello this is 
some text i wanted
to share with you
$ grep "^\|text" --color='always' a
hello this is 
some text i wanted     # "text" is highlighted
to share with you
Похоже, вам даже не нужно ^или $и просто "|text"работает.

Есть инструмент под названием ack. Вы можете найти его на http://beyondgrep.com , и это действительно инструмент, выходящий за рамки grep. Его наиболее распространенное использование - это заполнение этой роли find . -name "*.java" --print | xargs grep clazzили тому подобное. Потому что мы делаем это все время.

Просто ack clazzи вы получите результат. Ищет нужные файлы (не пытается выполнить поиск двоичных файлов) и также дает хороший цветной вывод.

Если вы используете его с --passthruопцией, он будет печатать весь входной поток, выделяя совпадающие области цветом.

--passthruРаспечатайте все строки, независимо от того, совпадают они или нет

Как указано в документации, если -используется для файла, он будет принимать STDIN:

Если указаны какие-либо файлы или каталоги, то проверяются только эти файлы и каталоги. ack также может выполнять поиск в STDIN, но только если не указаны аргументы файла или каталога или если один из них равен "-".

Таким образом, простите за catругань ( и за каламбур - см. ниже ) у вас может получиться:

$ cat file | ack --passthru pattern
$ cat file | ack --passthru pattern -

Это возьмет вывод канала и отправит его, через ackкоторый будут напечатаны все строки (с --passthru) с выделенным шаблоном.

Это именно тот инструмент, который вам нужен (и даже немного больше). Это стандартный пакет для многих менеджеров пакетов. См. http://beyondgrep.com/install/ для вашего фаворита.

_ /|
\'оО'
=(___)=
   Подтвердить --thpppt!

(Если вы не узнаете его, это кот Билл, хотя поиск изображений также может помочь — не нажимайте на набор Майли Сайрус)

Ack — отличный инструмент, но как он может распечатать весь ввод, просто выделив шаблон поиска? Как вы объясняете, обычно он используется как форма таргетинга grep -R, я не понимаю, как это может помочь ОП.
@terdon --passthruопция напечатает все строки и выделит интересующие образцы. Точно так же для работы со STDIN можно использовать дефис в качестве «имени» файла или вообще не использовать аргументы файла.
Я вижу, это имеет смысл. Поскольку вы сказали, что он действует как grep, я предположил, что он напечатает только соответствующую строку.
@terdon его режим по умолчанию - grepy. Хотя, как указывали люди с другими вариантами, можно обмануть grep, распечатав все строки и выделив интересующий текст. ack для этого не нужно обманывать — это один из стандартных вариантов. И спасибо за уточняющую правку.

Вы можете использовать grep -Cфлаг, который дает n строк контекста, например, grep -C 3будет печатать 3 строки до и после совпадения. Так же есть -Bи -Aдо и после.

Если вы хотите регулярно выделять заданные строки, например, определенные форматы журналов, возможно, стоит использовать python pygmentize с пользовательским лексером , поскольку он основан на регулярных выражениях, и вы будете удивлены, насколько это просто . Этот последний также имеет то преимущество, что является кросс-платформенным, хотя некоторые терминалы не очень хорошо отображают цвета.

Я поклонница хайлайтера Паоло Антинори. https://github.com/paoloantinori/hhighlighter

Плюсом этой команды является то, что она может выделять до 10 слов уникальными цветами. Просто передайте вывод команды hсо словами, которые нужно выделить.

Например tail -f /var/log/somelog.log | h "ERROR", будет производиться:

демо-1


Несколько примеров с его сайта:

демо-2 демо-3

Я написал небольшой скрипт, который будет окрашивать любую строку, которую вы ему дадите:

#!/usr/bin/env perl
use Getopt::Std;
use strict;
use Term::ANSIColor; 

my %opts;
getopts('hic:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

EoF
      exit(0);
    }

my $case_sensitive=$opts{i}||undef;
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
           'bold magenta', 'bold cyan', 'yellow on_magenta', 
           'bright_white on_red', 'bright_yellow on_red', 'white on_black');
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    $patterns[0]='\*';
}

# Setting $| to non-zero forces a flush right away and after 
# every write or print on the currently selected output channel. 
$|=1;

while (my $line=<>) 
{ 
    for (my $c=0; $c<=$#patterns; $c++){
    if($case_sensitive){
        if($line=~/$patterns[$c]/){
           $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ge;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
        }
      }
    }
    print STDOUT $line;
}

Если вы сохраните его как colorв каталоге, который находится в вашем каталоге, $PATHи сделаете его исполняемым ( chmod +x /usr/bin/color), вы можете раскрасить соответствующий шаблон следующим образом:

echo -e "foo\nbar\nbaz\nbib" | color -l foo,bib 

Это произведет:

  введите описание изображения здесь

Как написано, сценарий имеет предопределенные цвета для 10 различных шаблонов, поэтому если указать список, разделенный запятыми, как в приведенном выше примере, каждый из шаблонов, совпавших с ним, будет окрашен в другой цвет.

Я написал программу, чтобы сделать это некоторое время назад. Я называю это cgrep (для цвета grep).

Вы можете скачать его, скопировав раздел кода отсюда в пустой файл: http://wiki.tcl.tk/38096

Затем сделайте файл исполняемым и скопируйте его в один из ваших обычных каталогов bin.

Он написан на tcl, поэтому вам необходимо установить tcl (8.5 и выше). Но большинство дистрибутивов Linux в любом случае установили бы tcl, так как многие программы используют его (gitk, конфигурация ядра, ожидания и т. д.).

Синтаксис раскраски прост: regex option option ... Вы можете иметь столько регулярных выражений, сколько хотите. Вот пример, в котором ошибки окрашиваются в красный цвет, а предупреждения — в желтый:

tail -f logfile | cgrep '^.*WARNING.*$' -fg yellow '^.*ERROR.*$' -fg red -bg yellow

Самый простой способ выглядит так, я думаю:

tail -f logfile.log | grep -e 'error' -e '**'

введите описание изображения здесь

Не нужно ничего устанавливать.

Ну, у меня Fedora 21, и если я наберу

grep -E \|kk rs.c

он выведет все содержимое файла «rs.c», выделяя любые вхождения «kk».

Это в основном то же самое , что и ответ arielCo .
@Izzy: Синтаксис короче, поэтому я бы сказал, что это другой правильный ответ.
@NicolasRaoul, вот почему я тогда только оставил комментарий (но не пометил). В принципе, я надеялся, что постер немного расширится ;)

Вы можете использовать эту команду

grep --color --context=1000

Или короче

grep --col -1000

объясните.com - grep --color --context

Простой трюк состоит в том, чтобы также сопоставить пустую строку или начало строки; либо приводит к совпадению нулевой длины для всех строк:

grep --color -e 'REGEXP' -e ''
grep --color -e 'REGEXP' -e ^

Или (расширенный синтаксис регулярного выражения):

grep --color -E 'REGEXP|'
egrep --color 'REGEXP|'
Разве первый вариант не будет также фильтровать вывод REGEX? Я только что попробовал, и это так. Так что это не соответствует требованиям (только выделение, а не фильтр). Но второй вариант действительно делает то, что запросил ОП (проверено;).
Да, теперь это имеет смысл :) Отфильтровать по REGEX(выделяет этот термин) и по «ничего» (то есть «везде»). Могу ли я предложить вам включить это небольшое объяснение (слишком ясно, что оно делает), а затем мы удалим наши комментарии (для очистки)? Спасибо! А пока +1 от меня :)
Подойдет, но Федорки дал по существу тот же ответ выше (думаю, я не видел его, когда публиковал свой).
Должен признаться, я тоже этого не видел... (подсказка: нет "выше" или "ниже", так как порядок ответов зависит от того, какой фильтр вы установили ;)

Используйте less. Строка поиска, найденная с /помощью регулярного выражения, будет выделена.

В моем .bashrc у меня есть эта функция. Я называю это cgrep, но здесь я даю ему более подходящее имя.

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

Я нахожу это полезным, например, для отслеживания журналов, когда я хочу выделить ключевое слово, но видеть все, что происходит.

tail -f /var/log/SOMELOG | highlight KEYWORD
Должный кредит: я получил "^ |" идея из выбранного ответа @fedorqui. Спасибо :)

Вы можете просто направить свой вывод на:

sed "s/\([Ee][Rr][Rr][Oo][Rr]\)/`tput rev`\1`tput rmso`/"

Здесь я использую регулярное выражение, которое будет соответствовать «ошибке», «ОШИБКЕ», «ErRoR» и т. д. во всех 32 возможных вариантах.

У меня есть следующая функция, определенная в моем ~/.zshrc:

hl () {
    sed s/$1/$'\e[1;31m'\&$'\e[0;m'/
}

Используйте его с tail -f logfile.log | hl "error". Он добавляет escape-последовательность для светло-красного перед выделенным словом и сбрасывает цвет после слова. Вы можете найти другие цветовые коды здесь: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html