Убедить 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, но у него, похоже, тоже нет выбора.

Майкл Mrozek
источник
1
Возможная межсайтовая копия: stackoverflow.com/questions/981601/… Верхний ответ одинаков для обоих.
Сиро Сантилли 新疆 新疆 中心 法轮功 六四 事件
1
Вы можете использовать -C 9999вместо. -A 9999 -B 9999Я всегда делаю:grep -C 9999 pattern file
Neo

Ответы:

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

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

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

highlight () { grep --color -E "$1|$" "${@:1}" ; }
jacksonh
источник
14
Это чертовски круто!
gvkv
3
И как функция: highlight () { grep --color -E "$1|$" $2 ; }. Использование:highlight test yourfile
Stefan Lasiewski
2
@StefanLasiewski: "$2"также должны быть указаны.
Деннис Уильямсон
6
Лучше может быть: highlight () { grep --color -E "$1|$" "$@" }что позволяет файлы с пробелами в их именах и несколько файлов.
Майк ДеСимоне
15
@MikeDeSimone - но это также будет "$1"в файлах. Использованиеhighlight () { grep --color -E "$1|$" "${@:1}" }
Крис Даун
40
ack --passthru --color string file

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

ack-grep --passthru --color string file
Деннис Уильямсон
источник
1
О, это совершенно очевидно на странице руководства; Я слепой. Спасибо
Майкл Мрозек
шаблон для grap может быть указан явно с помощью --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
13

Другой способ сделать это правильно и переносимо с 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
don_crissti
источник
1
Или просто grep -F -e '' -e 'string'.
Стефан
Он работает для меня с GNU grep 2.25, busybox grep и набором инструментов семейной реликвии.
Стефан
ОК, мой плохой, seq 3 | grep -F -e '' -e 2выводит только 2 в 2.27 (и 2.26, но не 2.25 и не в git head). Только с -F(не без или с -E). 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:

less file

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

Это будет:

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

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

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

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

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

Стивен Пенни
источник
2

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

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

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

gvkv
источник
2

ripgrep

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

rg --passthru pattern file.txt

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

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

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

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

jlliagre
источник
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" "$@"
}
yurenchen
источник
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' интерпретируются строки bash с экранированными символами

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

egrep "^|main" testt.c

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

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

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

Доктор Беко
источник