В файле с двумя строками слов, grep только те строки, которые имеют оба слова из белого списка

У меня есть файл1:

green
yellow
apple
mango

и файл2:

red apple
blue banana
yellow mango
purple cabbage

Мне нужно найти элементы из file2, где оба слова принадлежат списку в file1. Итак, это должно показать:

желтое манго

Я старался:

awk < file2 '{if [grep -q $1 file1] && [grep -q $2 file1]; then print $0; fi}'

Я получаю синтаксическую ошибку.

3 ответа

Решение

Это сделает свое дело:

$ awk 'NR==FNR{a[$0];next}($1 in a)&&($2 in a)' file1 file2 
yellow mango

Объяснение:

NR это особый awk переменная отслеживает текущую строку на входе и FNR отслеживает текущую строку в каждом отдельном файле, поэтому условие NR==FNR верно только когда мы в первом файле. a является ассоциативным массивом, где ключи - каждая уникальная строка в первом файле. $0 значение текущей строки в awk, next оператор переходит на следующую строку в файле, чтобы следующая часть пропуска не выполнялась. Последняя часть прямолинейна, если первое поле $1 находится в массиве a а во втором поле выведите текущую строку. Блок по умолчанию в awk является {print $0} так что это неявно.

Вы можете сделать это с помощью bash, sed и grep:

grep -f <(sed 's/^/^/' file1) file2  | grep -f <(sed 's/$/$/' file1)

это немного неясно, поэтому я разобью это:

grep -f <file> читает последовательность шаблонов из файла и будет соответствовать любому из них.

<(...) является bash процесс подстановки и выполнит команду оболочки и создаст псевдофайл с выводом, который можно использовать вместо имени файла.

sed 's/^/^/' file1 вставляет ^ символ в начале каждой строки в файле1, превращая строки в шаблоны, которые будут соответствовать первому слову файла2.

sed 's/$/$/' file1 вставляет $ символ в конце, поэтому шаблоны будут соответствовать второму слову.

Редактировать: Использовать:

grep -f <(sed 's/^/^/;s/$/\b/' file1) file2  | grep -f <(sed 's/$/$/;s/^/\b/' file1)

чтобы обойти проблему, на которую указал Джонатан в своем комментарии.

Это очень хакерский подход, и, вероятно, его осуждают многие разработчики grep/sed. Кроме того, это, вероятно, зависит от терминала. Вы были предупреждены.

GNU grep в цветном режиме выделяет фрагменты входных данных, которые были сопоставлены с одним из шаблонов, что теоретически может использоваться в качестве теста для полного соответствия. Здесь это даже работает на практике, то есть с некоторой помощью GNU sed:

grep --color=always -f file1 file2 | sed -n '/^\x1b.*\x1b\[K *\x1b.*\x1b\[K$/ { s/\x1b\[K//g; s/\x1b[^m]*m//gp }'

Выход:

yellow mango

Обратите внимание, что шаблон sed предполагает использование столбцов, разделенных пробелами, в file2,

Другие вопросы по тегам