Я хочу найти файлы с «abc» И «efg» в этом порядке, и эти две строки находятся в разных строках в этом файле. Например: файл с содержанием:
blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..
Должно совпадать.
Ответы:
Grep недостаточно для этой операции.
pcregrep, который встречается в большинстве современных систем Linux, может использоваться как
где
-M
,--multiline
позволяют модели , чтобы соответствовать более чем одной линииТакже есть более новый pcre2grep . Оба предоставлены проектом PCRE .
pcre2grep доступен для Mac OS X через порты Mac как часть порта
pcre2
:и через Homebrew как:
или для pcre2
pcre2grep также доступен в Linux (Ubuntu 18.04+)
источник
-M, --multiline
- разрешить шаблонам соответствовать более чем одной строке.'abc.*(\n|.)*?efg'
.*
->'abc(\n|.)*?efg'
чтобы сделать регулярное выражение короче (и быть педантичным)pcregrep
делает вещи проще, ноgrep
тоже будет работать. Например, см stackoverflow.com/a/7167115/123695Я не уверен, возможно ли это с помощью grep, но sed делает это очень просто:
источник
sed
, но если никогда не видел такого выражения раньше.Вот решение, вдохновленное этим ответом :
если 'abc' и 'efg' могут быть в одной строке:
если 'abc' и 'efg' должны быть в разных строках:
Params:
-z
Обрабатывайте ввод как набор строк, каждая из которых заканчивается нулевым байтом вместо новой строки. то есть grep обрабатывает ввод как одну большую строку.-l
напечатать имя каждого входного файла, из которого обычно выводился бы вывод.(?s)
активировать PCRE_DOTALL, что означает «.» находит любой символ или перевод строки.источник
l
. AFAIK нет-1
варианта номера .-z
параметрах указывается grep для обработки символов новой строки,zero byte characters
то зачем нам(?s)
в регулярном выражении? Если это уже не символ новой строки, не должны ли.
быть в состоянии сопоставить его напрямую?sed должно быть достаточно, как указано выше в постере ЖЖ,
вместо! d вы можете просто использовать p для печати:
источник
Я сильно полагался на pcregrep, но с более новым grep вам не нужно устанавливать pcregrep для многих его функций. Просто используйте
grep -P
.В примере с вопросом OP, я думаю, что следующие варианты работают хорошо, со вторым лучшим соответствием, как я понимаю вопрос:
Я скопировал текст как / tmp / test1, удалил «g» и сохранил как / tmp / test2. Вот выходные данные, показывающие, что первый показывает совпадающую строку, а второй показывает только имя файла (типично -o - показать совпадение, а типичное -l - показать только имя файла). Обратите внимание, что «z» необходимо для многострочного, а «(. | \ N)» означает совпадение с «чем-либо, кроме newline» или «newline» - т.е. с чем угодно:
Чтобы определить, является ли ваша версия достаточно новой, запустите
man grep
и посмотрите, появляется ли что-то похожее на это сверху:Это из GNU grep 2.10.
источник
Это можно легко сделать, используя сначала
tr
замену новой строки другим символом:Здесь я использую символ тревоги
\a
(ASCII 7) вместо новой строки. Это почти никогда не встречается в вашем тексте, иgrep
может совпадать с ним.
или специально соответствовать\a
.источник
\0
и, следовательно, нуждалсяgrep -a
и соответствовал\x00
… Вы помогли мне упростить!echo $log | tr '\n' '\0' | grep -aoE "Error: .*?\x00Installing .*? has failed\!" | tr '\0' '\n'
сейчасecho $log | tr '\n' '\a' | grep -oE "Error: .*?\aInstalling .*? has failed\!" | tr '\a' '\n'
grep -o
.awk one-liner:
источник
abc
конца до конца файла, если конечный шаблон отсутствует в файле или отсутствует последний конечный шаблон. Вы можете это исправить, но это значительно усложнит сценарий./efg/
из вывода?Вы можете сделать это очень легко, если вы можете использовать Perl.
Вы также можете сделать это с помощью одного регулярного выражения, но это включает в себя все содержимое файла в одну строку, что может в конечном итоге занять слишком много памяти большими файлами. Для полноты, вот этот метод:
источник
.*?
), чтобы получить минимальное совпадение.Я не знаю, как бы я это сделал с grep, но я бы сделал что-то подобное с awk:
Вы должны быть осторожны, как вы это делаете, хотя. Вы хотите, чтобы регулярное выражение соответствовало подстроке или всему слову? добавьте теги \ w по мере необходимости. Кроме того, хотя это строго соответствует тому, как вы изложили пример, оно не совсем работает, когда abc появляется во второй раз после efg. Если вы хотите справиться с этим, добавьте if в случае необходимости в / abc / case и т. Д.
источник
К сожалению, вы не можете. Из
grep
документов:источник
grep -Pz
Если вы хотите использовать контексты, этого можно достичь, набрав
Это отобразит все между «abc» и «efg», если они находятся в пределах 500 строк друг от друга.
источник
Если вам нужно, чтобы оба слова были близко друг к другу, например, не более 3 строк, вы можете сделать это:
Тот же пример, но фильтрация только файлов * .txt:
А также вы можете заменить
grep
команду наegrep
команду, если вы также хотите найти с регулярными выражениями.источник
Несколько дней назад я выпустил альтернативу grep, которая поддерживает это напрямую, либо с помощью многострочного сопоставления, либо с использованием условий - надеюсь, это будет полезно для некоторых людей, которые ищут здесь. Вот как будут выглядеть команды для примера:
Multiline:
условия:
Вы также можете указать, что 'efg' должен следовать за 'abc' в определенном количестве строк:
Вы можете найти больше информации на sift-tool.org .
источник
sift -lm 'abc.*efg' testfile
работает, потому что совпадение является жадным и поглощает все строки до последнейefg
в файле.Хотя опция sed является самой простой и легкой, однострочная версия LJ, к сожалению, не самая портативная. Те, кто застрял с версией C Shell, должны избежать челки:
Это, к сожалению, не работает в Bash et al.
источник
источник
Вы можете использовать grep, если вы не заинтересованы в последовательности паттерна.
пример
grep -l
найдет все файлы, которые соответствуют первому шаблону, а xargs будет grep для второго шаблона. Надеюсь это поможет.источник
С серебряным искателем :
похож на ответ на предъявителя кольца, но вместо этого используется ag. Скоростные преимущества серебряного искателя могли бы здесь проявиться.
источник
(echo abctest; echo efg)|ag 'abc.*(\n|.)*efg'
не совпадаетЯ использовал это для извлечения последовательности fasta из мультифаст-файла, используя опцию -P для grep:
Ядро регулярного выражения - это то,
[^>]
что переводится как «не больше, чем символ»источник
В качестве альтернативы ответа Бала Мохан, можно применять порядок моделей с использованием только
grep
,head
иtail
:Этот не очень красивый, хотя. Форматируется более наглядно:
Это напечатает имена всех файлов , где
"pattern2"
появляется после того, как"pattern1"
, или когда оба появляются на одной и той же линии :объяснение
tail -n +i
- печатать все строки послеi
й включительноgrep -n
- предварительно сопоставлять совпадающие строки с их номерамиhead -n1
- печатать только первый рядcut -d : -f 1
- напечатать первый вырезанный столбец, используя:
в качестве разделителя2>/dev/null
-tail
вывод ошибки тишины, которая возникает, если$()
выражение возвращает пустое значениеgrep -q
- замолчатьgrep
и немедленно вернуться, если совпадение найдено, так как нас интересует только код выходаисточник
&>
? Я тоже этим пользуюсь, но нигде не видел, чтобы это было задокументировано. Кстати, почему мы должны так замалчивать grep?grep -q
тоже не справится?&>
говорит bash перенаправить как стандартный вывод, так и стандартную ошибку, см. REDIRECTION в руководстве по bash. Вы очень правы в том , что мы могли бы также сделатьgrep -q ...
вместоgrep ... &>/dev/null
, хороший улов!Это тоже должно работать ?!
$ARGV
содержит имя текущего файла при чтении изfile_list /s
поисков модификатора через новую строку .источник
Filepattern
*.sh
важен для предотвращения проверки каталогов. Конечно, некоторые испытания могут предотвратить это тоже.The
ищет максимум 1 совпадение и возвращает (-n) номер белья. Если совпадение было найдено (test -n ...), найдите последнее совпадение с efg (найдите все и возьмите последнее с tail -n 1).
еще продолжить.
Поскольку в результате получается что-то вроде этого,
18:foofile.sh String alf="abc";
нам нужно отрезать от ":" до конца строки.Должен возвращать положительный результат, если последнее совпадение 2-го выражения прошло после первого совпадения первого.
Затем мы сообщаем имя файла
echo $f
.источник
Почему бы не что-то простое, как:
возвращает 0 или положительное целое число.
egrep -o (Показывает только совпадения, трюк: несколько совпадений в одной строке производят многострочный вывод, как если бы они были в разных строках)
grep -A1 abc
(выведите abc и строку после него)grep efg | wc -l
(0-n число строк efg, найденных после abc в той же или следующих строках, результат можно использовать в «если»)grep может быть изменен на egrep и т. д., если требуется сопоставление с образцом
источник
Если у вас есть некоторая оценка расстояния между двумя строками «abc» и «efg», которые вы ищете, вы можете использовать:
Таким образом, первый grep вернет строку с «abc» плюс # num1 строки после нее и # num2 строки после нее, а второй grep просеет все эти строки, чтобы получить «efg». Тогда вы будете знать, в каких файлах они появляются вместе.
источник
С ugrep вышел несколько месяцев назад:
Этот инструмент сильно оптимизирован по скорости. Он также совместим с GNU / BSD / PCRE-grep.
Обратите внимание, что мы должны использовать ленивое повторение
+?
, если вы не хотите сопоставлять все строкиefg
вместе до последнегоefg
в файле.источник
Это должно работать:
Если найдено более одного совпадения, вы можете отфильтровать с помощью grep -v
источник