Как найти все файлы, содержащие различные строки из длинного списка комбинаций строк?

Я все еще очень новичок в инструментах командной строки (используя мой терминал Mac OSX), и надеюсь, что я не пропустил ответ в другом месте, но я искал часы.

У меня есть текстовый файл (назовем его strings.txt), содержащий 200 комбинаций из 3 строк. [ Редактировать 2017/01/30 ] Первые пять строк выглядят так:

"surveillance data" "surveillance technology" "cctv camera" "social media" "surveillance techniques" "enforcement agencies" "social control" "surveillance camera" "social security" "surveillance data" "security guards" "social networking" "surveillance mechanisms" "cctv surveillance" "contemporary surveillance" 

Обратите внимание, что я могу изменить файл strings.txt в любом другом формате, если только фразы с биграммами / 2-мя словами, такими как данные наблюдения в строке 1, остаются вместе. (Это означает, что я могу удалить кавычки, если это необходимо, что касается ответа @MichaelVehrs ниже).

Теперь я хочу искать в каталоге более 800 файлов для тех файлов, которые содержат хотя бы одну из комбинаций строк (в любом месте файла). Моя первоначальная идея заключалась в том, чтобы использовать egrep с файлом шаблона следующим образом:

 egrep -i -l -r -f strings.txt file_directory 

Тем не менее, я могу заставить это работать, если есть одна строка в строке. Это нежелательно, потому что мне нужно, чтобы идентифицированные файлы содержали все три строки данного шаблона. Есть ли способ добавить какой-то оператор AND в файл шаблона grep? Или есть другой способ добиться того, что я хочу, используя другую функцию / инструмент? Большое спасибо!

Редактировать 2017/01/30

Ответ @MichaelVehrs ниже был очень полезным; Я отредактировал его следующим образом:

 while read one two three four five six do grep -ilFr "$one $two" *files* | xargs grep -ilFr "$three $four" | xargs grep -ilFr "$five $six" done < *patternfile* | sort -u 

Этот ответ работает, когда файл шаблона содержит строки без кавычек. К сожалению, это только похоже на шаблон в первой строке файла шаблона. Кто-нибудь знает, почему?

Редактировать 2017/01/29

Аналогичный вопрос о grepping нескольких значениях задавался раньше , но мне нужна логика AND , чтобы соответствовать одной из трехстрочных комбинаций из файла strings.txt файла шаблона в других файлах. Я понимаю, что формат strings.txt, возможно, придется изменить для соответствия, чтобы работать, и был бы признателен за предложения.

Поскольку agrep похоже, не присутствует в вашей системе, посмотрите на эту альтернативу, основанную на sed и awk, чтобы применить grep и операции от шаблонов, прочитанных локальным файлом.

PS: Поскольку вы используете osx, я не уверен, что версия awk у вас будет поддерживать более широкое использование.

awk может имитировать grep с помощью AND нескольких шаблонов в этом использовании:
awk '/pattern1/ && /pattern2/ && /pattern3/'

Таким образом, вы можете преобразовать свой файл шаблонов из этого:

 $ cat ./tmp/d1.txt "surveillance data" "surveillance technology" "cctv camera" "social media" "surveillance techniques" "enforcement agencies" "social control" "surveillance camera" "social security" "surveillance data" "security guards" "social networking" "surveillance mechanisms" "cctv surveillance" "contemporary surveillance" 

К этому:

 $ sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' ./tmp/d1.txt /surveillance data/ && /surveillance technology/ && /cctv camera/ /social media/ && /surveillance techniques/ && /enforcement agencies/ /social control/ && /surveillance camera/ && /social security/ /surveillance data/ && /security guards/ && /social networking/ /surveillance mechanisms/ && /cctv surveillance/ && /contemporary surveillance/ 

PS: Вы можете перенаправить вывод в другой файл с помощью >anotherfile другого файла в конце, или вы можете использовать параметр sed -i для внесения изменений на месте в одном и том же файле шаблонов условий поиска.

Тогда вам просто нужно прокормить awk с помощью шаблонов, отформатированных в awk из этого файла шаблонов:

 $ while IFS= read -r line;do awk "$line" *.txt;done<./tmp/d1.txt #d1.txt = my test pattern file 

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

 while IFS= read -r line;do line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line") awk "$line" *.txt done <./tmp/d1.txt 

Или как однострочный:

 $ while IFS= read -r line;do line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line"); awk "$line" *.txt;done <./tmp/d1.txt 

Выше команды возвращают правильные И результаты в мои тестовые файлы, которые выглядят так:

 $ cat d2.txt This guys over there have the required surveillance technology to do the job. The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera. $ cat d3.txt All surveillance data are locked. All surveillance data are locked and guarded by security guards. There are several surveillance mechanisms (ie cctv surveillance, contemporary surveillance, etv) 

Результаты:

 $ while IFS= read -r line;do awk "$line" *.txt;done<./tmp/d1.txt #or while IFS= read -r line;do line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line"); awk "$line" *.txt;done <./tmp/d1.txt The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera. There are several surveillance mechanisms (ie cctv surveillance, contemporary surveillance, etv) 

Обновить:
Выше awk-решение печатает содержимое соответствующих файлов txt.
Если вы хотите отображать имена файлов вместо содержимого, тогда при необходимости используйте следующий awk:

 awk "$line""{print FILENAME}" *.txt 

Проблема немного неудобна, но вы можете приблизиться к ней следующим образом:

 while read one two three four five six do grep -lF "$one $two" *files* | xargs grep -lF "$three $four" | xargs grep -lF "$five $six" done < patterns | sort -u 

Это предполагает, что ваш файл шаблона содержит ровно шесть слов в строке (три шаблона по два слова каждый). Логический and реализуется путем объединения трех последовательных фильтров ( grep ). Обратите внимание, что это не особенно эффективно. Решение awk , вероятно, будет быстрее.

Я бы использовал perl , что-то вроде:

 perl -MFile::Find -MClone=clone -lne ' # parse the strings.txt input, here looking for the sequences of # 0 or more characters (.*?) in between two " characters for (/"(.*?)"/g) { # @needle is an array of associative arrays whose keys # are the "strings" for each line. $needle[$n]{$_} = undef; } $n++; END{ sub wanted { return unless -f; # only regular files my $needle_clone = clone(\@needle); if (open FILE, "<", $_) { LINE: while (<FILE>) { # read the file line by line for (my $i = 0; $i < $n; $i++) { for my $s (keys %{$needle_clone->[$i]}) { if (index($_, $s)>=0) { # if the string is found, we delete it from the associative # array. delete $needle_clone->[$i]{$s}; unless (%{$needle_clone->[$i]}) { # if the associative array is empty, that means we have # found all the strings for that $i, that means we can # stop processing, and the file matches print $File::Find::name; last LINE; } } } } } close FILE; } } find(\&wanted, ".") }' /path/to/strings.txt 

Это означает, что мы минимизируем количество поисков строк.

Здесь мы обрабатываем файлы по строкам. Если файлы достаточно малы, вы можете обработать их в целом, что упростит его и может повысить производительность.

Обратите внимание, что он ожидает, что файл списка будет находиться в:

  "surveillance data" "surveillance technology" "cctv camera" "social media" "surveillance techniques" "enforcement agencies" "social control" "surveillance camera" "social security" "surveillance data" "security guards" "social networking" "surveillance mechanisms" "cctv surveillance" "contemporary surveillance" 

формат, с числом (не должно быть 3) строк с кавычками (с двойной кавычкой) на каждой строке. Цитируемые строки не могут содержать символы двойной кавычки. Символ двойной кавычки не является частью просматриваемого текста. То есть, если файл списка содержит:

 "A" "B" "1" "2" "3" 

который будет сообщать о пути всех обычных файлов в текущем каталоге и ниже, которые содержат либо

  • и A и B
  • или (не являющиеся исключительными или ) все 1 , 2 и 3

где-нибудь в них.

Это еще один подход, который, похоже, работает в моих тестах.

Я скопировал ваши данные файлов строк в файл с именем d1.txt и переместил его в отдельный каталог (т. Е. Tmp), чтобы избежать более позднего grep, чтобы соответствовать файлу строк в том же файле (d1.txt).

Затем вставьте в этот файл строк (d1.txt в моем случае) полуплотность между каждым поисковым термином со следующей командой: sed -i 's/" "/";"/g' ./tmp/d1.txt

 $ cat ./tmp/d1.txt "surveillance data" "surveillance technology" "cctv camera" "social media" "surveillance techniques" "enforcement agencies" "social control" "surveillance camera" "social security" "surveillance data" "security guards" "social networking" "surveillance mechanisms" "cctv surveillance" "contemporary surveillance" $ sed -i 's/" "/";"/g' ./tmp/d1.txt $ cat ./tmp/d1.txt "surveillance data";"surveillance technology";"cctv camera" "social media";"surveillance techniques";"enforcement agencies" "social control";"surveillance camera";"social security" "surveillance data";"security guards";"social networking" "surveillance mechanisms";"cctv surveillance";"contemporary surveillance" 

Затем удалите двойные кавычки, используя команду sed 's/"//g' ./tmp/d1.txt PS: Это может быть действительно не нужно, но я удалил двойные кавычки для тестирования.

 $ sed -i 's/"//g' ./tmp/d1.txt && cat ./tmp/d1.txt surveillance data;surveillance technology;cctv camera social media;surveillance techniques;enforcement agencies social control;surveillance camera;social security surveillance data;security guards;social networking surveillance mechanisms;cctv surveillance;contemporary surveillance 

Нет, вы можете grep все файлы в текущем каталоге с программой agrep которая предназначена для обеспечения многократного grep grep с помощью операции AND.

agrep требует, чтобы несколько шаблонов были разделены полуколодой ; для оценки как И.

В моих тестах я создал два примера файлов с содержимым:

 $ cat d2.txt This guys over there have the required surveillance technology to do the job. The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera. $ cat d3.txt All surveillance data are locked. All surveillance data are locked and guarded by security guards. There are several surveillance mechanisms (ie cctv surveillance, contemporary surveillance, etv) 

Выполнение agrep в текущем каталоге возвращает правильные строки (с AND) и имена файлов:

 $ while IFS= read -r line;do agrep "$line" *;done<./tmp/d1.txt d2.txt: The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera. d3.txt: There are several surveillance mechanisms (ie cctv surveillance, contemporary surveillance, etv)