Разноцветный Grep

30

Я пытаюсь заставить каждую команду grep выделять ее результаты другим цветом. Я могу сделать это вручную с помощью такой строки:

ls -l GREP_COLORS='mt=01;32' grep c | GREP_COLORS='mt=01;31' grep o | GREP_COLORS='mt=01;34' grep n | GREP_COLORS='mt=01;36' grep f

Каждый cсимвол будет выделен зеленым цветом, а каждый oсимвол - красным и т. Д.

Чтобы этот пример работал, вам нужно убедиться, что вы всегда используете --color=alwaysкоманды grep. Я установил это в моем, .bashrc поэтому у grep всегда будут цвета:

export GREP_OPTIONS='--color=always'


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

Я сделал несколько попыток, но, как ни странно, эта, похоже, работает «лучше». У меня есть это в моем .bashrc:

alias mg="mygrep"
mygrep(){
    # define possible colors
    COLORS=("01;32" "01;31" "01;34" "01;36")
    COUNTER=0
    NUM=0
    # as long as the color has already been used, keep searching
    while [ -f /home/lior/Desktop/mygrep_$NUM ]; do
        # get a random index
        let NUM=`shuf --input-range=0-$(( ${#COLORS[*]} - 1 )) | head -1`
        wait ${!}
        $(( COUNTER+=1 ))
        if [ "$COUNTER" -ge ${#COLORS[@]} ]; then
            # remove all color locks
            rm /home/lior/Desktop/mygrep_*
            wait ${!}
        fi
    done
    # mark this color as used
    touch /home/lior/Desktop/mygrep_$NUM
    wait ${!}

    # lets go!
    GREP_COLORS="mt=${COLORS[$NUM]}" grep "$@"
}

Я использую этот псевдоним так:

ll | mg c | mg o | mg n | mg f

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

Похоже, что оболочка проходит через каждую конвейерную команду, предыдущая функция еще не завершила свое выполнение. Он пытается удалить файлы, которые больше не существуют. Я не слишком уверен, откуда command not foundприходят эти другие ошибки.

Как видите, я добавил несколько waitкоманд, чтобы попытаться завершить манипулирование файлами, но, похоже, это работает не слишком хорошо. Еще одна вещь, которую я уже пробовал, - это использовать разделяемую память, /dev/shmно она дала аналогичные результаты.

Как мне добиться желаемых результатов?

Заметка:

Я ищу ответы, которые просто обертывают команду grep, так как она обладает множеством функциональных возможностей, которые я хочу использовать, и намереваюсь вставить другую логику между каналами, поэтому я не хочу предоставлять все условия поиска одновременно. Я также не ищу другие инструменты типа "grep like". Извините за @terdon, который уже опубликовал отличное предложение Perl.

Lix
источник
Ваш первый пример не соответствует тому, что вы объясняете в оставшейся части, просто говоря.
Бернхард
@bernhard Я не понимаю, что вы имеете в виду ... Я собираюсь использовать мой псевдоним как часть более крупной команды, использующей трубопроводы ... Пожалуйста, дайте мне знать, о каком противоречии вы говорите ...
Lix
Я думал, ты тоже хотел использовать свой псевдоним вне каналов. Во всяком случае, ваш первый пример не работает для меня. Ты пробовал alias mg="mygrep; grep"?
Бернхард
@Bernhard - я работаю над коробкой Ubuntu 12.04. Я не удивлюсь, если будут небольшие различия ... Я попробовал ваше предложение, проблема в том, что он сам по себе mygrep;превращается в новую команду, и поток данных теряется. Входящая труба из lsбудет передана, mygrep;а не grep. По крайней мере, так я это понимаю.
Ликс
@ Бернхард - А ... Я думаю, я знаю, почему это не сработало для тебя. Вы должны убедиться, что у вас есть --color=alwaysвсе ваши команды grep. Я установил это глобально в моем .bashrc. Я отредактировал это в посте.
Lix

Ответы:

6

Вот другой подход. У меня есть небольшой Perl-скрипт, который я уже разместил в другом ответе, который выделит предоставленные пользователем шаблоны в разных цветах. Слегка измененная версия скрипта будет действовать так grep:

#!/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_blue', 
       'bright_white on_yellow', '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=<>) 
{ 
    my $want=0;
    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;
           $want++;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
          $want++;
        }
      }
    }
print STDOUT $line if $want>0;
}

Если вы сохраните этот скрипт как cgrepгде-то в своем PATHфайле и сделаете его исполняемым, вы можете указать до 10 различных шаблонов, каждый из которых будет напечатан различным цветом:

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

$ cgrep -h
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;
Тердон
источник
5

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

#!/usr/bin/env bash
color_index_file=~/.gitcolor
color_index_lock_file=/tmp/$(basename $0)

colors=()
for index in {31..34}
do
    colors+=("01;$index")
done

until mkdir "$color_index_lock_file" 2>/dev/null
do
    :
done

color_index=$(($(cat "$color_index_file" || echo 0) + 1))

if [[ $color_index -ge ${#colors[@]} ]]
then
    color_index=0
fi

printf "$color_index" > "$color_index_file"
rmdir "$color_index_lock_file"

GREP_COLORS="mt=01;${colors[$color_index]}" grep --color=always "$@"

Тест, предполагая, что вы назвали свою копию cgrepи поместили ее в свой PATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz
l0b0
источник
Единственные переменные, которые действительно нужно поддерживать, это COLOR_INDEXи GREP_COLORS. Я попытался экспортировать их в конце функции без успеха. Это то, что вы имели в виду? Просто иметь export VAR, верно?
Lix
Ох - и да .. глупая опечатка там с COLOR_TOGGLE. Спасибо за то, что поймали это :)
Lix
1
@ l0b0 Экспорт у меня тоже не работает, сейчас надо понизить голос, пока он действительно не ответит на вопрос.
Бернхард
@ Bernhard Это работает для вас?
10
Спасибо за ваш вклад! Я включил ваше grep "$@"предложение - это отсортировало псевдоним для запуска функции, а затем grep.
Lix
1

Если вы хорошо разбираетесь в регулярных выражениях, вы можете проверить grc и grcat. grc вызывает grcat.

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

В зависимости от того, что вы имеете в виду для окончательного сценария, вы можете раскрасить вывод только одной командой.

Хитрость заключается в правильном определении регулярных выражений для каждого «поля» в вашем источнике данных. Это будет намного проще, если ваши данные будут относительно однородными по структуре.

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

Существует также команда tput, которую можно использовать для отправки информации (например, изменения цвета) непосредственно на ваше оконечное устройство.

Оба подхода описаны ниже. В нем говорится о команде поиска, но она может быть применена к выводу любой команды.

Цветной НАЙТИ выход?

Джо
источник