Я хочу найти файлы, которые имеют "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, может использоваться как
pcregrep -M 'abc.*(\n|.)*efg' test.txt
, где -M, --multiline позволяют шаблонам соответствовать более чем одной строке
Существует более новый pcre2grep также. Оба предоставлены проектом PCRE .
pcre2grep доступен для Mac OS X через Порты Mac как часть порта pcre2
:
% sudo port install pcre2
и через Homebrew как:
% brew install pcre
или для pcre2
% brew install pcre2
Это можно сделать очень легко, если вы умеете использовать Perl.
perl -ne 'if (/abc/) { $abc = 1; next }; print "Found in $ARGV\n" if ($abc && /efg/); }' yourfilename.txt
Вы также можете сделать это с помощью одного регулярного выражения, но для этого нужно объединить все содержимое файла в одну строку, что может привести к тому, что большие файлы займут слишком много памяти. Для полноты, вот этот метод:
perl -e '@lines = <>; $content = join("", @lines); print "Found in $ARGV\n" if ($content =~ /abc.*efg/s);' yourfilename.txt
Я не уверен, возможно ли это с grep, но sed упрощает его:
sed -e '/abc/,/efg/!d' [file-with-content]
Я не знаю, как бы я сделал это с помощью grep, но я бы сделал что-то вроде этого с awk:
awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo
Однако вы должны быть осторожны, как вы это делаете. Вы хотите, чтобы регулярное выражение соответствовало подстроке или всему слову? при необходимости добавьте теги \ w. Кроме того, хотя это строго соответствует тому, как вы указали пример, это не совсем работает, когда abc появляется второй раз после efg. Если вы хотите справиться с этим, добавьте, если необходимо, в / abc / case и т. Д.
#!/bin/bash
shopt -s nullglob
for file in *
do
r=$(awk '/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}' file)
if [ "$r" -eq 1 ];then
echo "Found pattern in $file"
else
echo "not found"
fi
done
К сожалению, вы не можете. Из документации grep
:
grep ищет именованные входные ФАЙЛЫ (или стандартный ввод, если файлы не имеют имен или если в качестве имени файла указан один дефис-минус (-)) для строки , содержащие совпадение с заданным ШАБЛОНОМ.