Исключить текстовые строки, содержащиеся в текстовом файле

avatar
Jalan
8 августа 2021 в 18:51
88
2
0

У меня есть текстовый файл, содержащий следующие строки:

$ cat HELLO.DAT
A
FOX
IS
JUMPING

У меня есть другой текстовый файл, содержащий

$ cat WORLD.DAT
A CAT
RUNNING FOX
IS GOD
AND JUMPING JACK

Мне нужен следующий вывод

CAT
RUNNING
GOD
AND JACK

Я пытался

while read -r line; do grep -v "$line" WORLD.DAT; done < HELLO.DAT

но вывод

RUNNING FOX
IS GOD
A CAT
IS GOD
AND JUMPING JACK
A CAT
RUNNING FOX
AND JUMPING JACK
A CAT
RUNNING FOX
IS GOD

Поэтому он удаляет всю строку после того, как найдено совпадение, а также выполняет цикл по WORLD.DAT для каждого списка в HELLO.DAT

Я тоже пытался

grep -v -f HELLO.dat WORLD.dat but then no output.

Как это исправить?

Источник
markp-fuso
8 августа 2021 в 19:33
0

пример ввода/вывода показывает, что строка №1 из HELLO.DAT применяется к строке №1 из WORLD.DAT, строка №2 из HELLO.DAT применяется к строке №2 из WORLD.DAT и т. д.; намерение ограничить удаление одной и той же строкой # или следует применять записи из HELLO.DAT ко всем строкам из WORLD.DAT? например, предположим, что строка № 4 (WORLD.DAT) — это AND JUMPING A JACK ... вы ожидаете, что вывод будет AND A JACK (удалить просто JUMPING) или <7888586097406>) или <78885863097406> >оба A и JUMPING)?

Jalan
8 августа 2021 в 19:36
1

@markp-fuso Цель состоит не в удалении из той же строки #. Следует искать строки в файле черного списка в любом порядке и номере строки и удалять их.

Ответы (2)

avatar
Nishant Gupta
8 августа 2021 в 19:57
1

Решение вашей проблемы с помощью команды 'sed':

while read -r line
do 
  sed -i 's/\b'$line'\s*\b//g' WORLD.Dat
done < Hello.dat
sed -i 's/\s*$//g' WORLD.Dat

'sed' заменит слова в WORLD.DAT (совпадающие со словами в HELLO.DAT) пустой строкой.

'sed' в третьей строке может обрабатывать слова, имеющие конечные и начальные пробелы и только начальные пробелы.

'sed' в последней строке удаляет пробелы в конце строки.

Jalan
8 августа 2021 в 20:18
0

Есть ли трубка перед sed в последней строке?

Nishant Gupta
9 августа 2021 в 13:35
0

Нет. Вы можете сохранить его как файл .sh или .bash и выполнить его.

avatar
Socowi
8 августа 2021 в 19:21
1

grep -v исключает целые строки, но вы хотите исключить только слова из строки. Без -v вы могли бы использовать -o для печати только соответствующей части. К сожалению, в режиме -v нет эквивалента для -o, который просто удаляет совпадающую часть. Поэтому вам нужна другая команда.

Следующая команда awk читает строки из первого файла и удаляет эти слова из второго файла:

awk 'NR==FNR {a[$0]} NR!=FNR {
  for (i=1;i<=NF;++i) { if ($i in a) $i="" }
  $0=$0; $1=$1; print
}' HELLO.DAT WORLD.DAT

Обратите внимание, что мы удаляем только целые слова, разделенные пробелом. A из первого файла не удаляет A в CAT из второго файла.

NR==FNR — это идиома awk для проверки обработки первого файла.

$0=$0; $1=$1 сжимает любую последовательность пробелов. Это далеко не идеально, но также необходимо, поскольку в ожидаемом выводе не было начального пробела перед CAT или двух пробелов в AND JACK.

.
Jalan
9 августа 2021 в 06:53
0

Просто небольшое уточнение. Это работает, только если я выполняю построчный поиск, то есть слова в HELLO.dat также присутствуют в той же строке # в WORLD.dat. Отличным решением для снятия этого ограничения является использование awk 'NR==FNR {a[$0]} NR!=FNR { for (k in a) { gsub(k, "") } $0=$0; 1 доллар = 1 доллар; print }' HELLO.DAT WORLD.DAT указывает на Франсиско Лобоса.

Socowi
9 августа 2021 в 08:26
0

@Jalan Я так не думаю, см. здесь. В этом ответе порядок входного файла не имеет значения. Использование gsub было бы шагом назад, потому что оно удаляет каждую подстроку, например. буква А в CAT. Кроме того, gsub будет интерпретировать регулярные выражения.