it-swarm-ru.tech

Убедить grep вывести все строки, а не только те, которые совпадают

Скажем, у меня есть следующий файл:

$ 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

Screenshot of the two commands

Если grep не может этого сделать, есть ли другой инструмент командной строки, который предлагает такую ​​же функциональность? Я возился с ack , но, похоже, у него тоже нет выбора.

127
Michael Mrozek
grep --color -E "test|$" yourfile

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

Вы можете легко создать из него функцию, например так:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
194
jacksonh
ack --passthru --color string file

для Ubuntu и Debian используйте ack-grep вместо ack

ack-grep --passthru --color string file
40
Paused until further notice.

Другой способ сделать это правильно и переносимо с помощью 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
13
don_crissti

У меня есть следующая функция, которую я использую для таких вещей:

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 и т. д.), я бы сказал, что это в значительной степени универсальное решение.

11
iconoclast

Вместо использования Grep вы можете использовать Less:

less file

Искать вот так: /pattern Enter

Это будет:

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

Чтобы перейти к следующей соответствующей строке: n

Чтобы перейти к предыдущей строке соответствия: N

Для переключения выделения: Esc u

Также вы можете изменить выделение цветом , если хотите.

3
Steven Penny

Ты можешь попробовать:

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

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

2
gvkv

Ни один из приведенных ответов не дает переносимого решения.

Вот портативный1 Функция оболочки I уже опубликована в закрытом дублирующем вопросе, для которого не требуются нестандартные инструменты или нестандартные расширения, поставляемые с Perl, ack, ggrep, gsed, bash и ​​т.п., но нужны только оболочка POSIX и обязательные утилиты POSIX sed и ​​printf:

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

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

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 Пока ваш терминал поддерживает escape-последовательности цветов ANSI.

2
jlliagre

ripgrep

Используйте ripgrep со своим --passthru параметр:

rg --passthru pattern file.txt

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

--passthru - Вывести как совпадающие, так и не совпадающие строки.

Еще один способ добиться аналогичного эффекта - изменить шаблон так, чтобы он соответствовал пустой строке. Например, если вы ищете с помощью rg foo затем используя rg "^|foo" вместо этого будет выдавать каждую строку в каждом искомом файле, но будут выделены только вхождения foo. Этот флаг включает такое же поведение без необходимости изменения шаблона.

2
kenorb

Есть гораздо более простой способ сделать это для GNU grep, но я не думаю, что он переносимый (т. Е. BSD grep):

В трубе:

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

На файл:

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

Кредит идет на ответ Сайруса здесь .

1
Erik Nomitch

Версия 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" "[email protected]"
}
0
yurenchen

ОП попросил 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' это строки bash с интерпретированными экранированными символами

Что касается grep, он также работает с использованием ^ (начало строки) вместо $ (конец линии). Пример:

egrep "^|main" testt.c

И просто, чтобы показать этот сумасшедший псевдоним, который Я НЕ РЕКОМЕНДУЮ, вы можете даже позволить открывать кавычки:

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

все работает! :) Не беспокойтесь, если вы забудете закрыть кавычку, bash запомнит вас с помощью символа продолжения строки.

0
Dr Beco