Как удалить строки, которые появляются в файле B из другого файла A?
у меня большой на (состоящий из писем), одна строка для каждой почты. У меня тоже есть другой файл B который содержит другой набор писем.
какую команду я бы использовал, чтобы удалить все адреса, которые появляются в файле B из файла A.
Так, если файл содержал:
A
B
C
и файл B содержит:
B
D
E
затем файл A должен быть оставлен с:
A
C
Теперь я знаю, что это вопрос это можно было бы спросить чаще, но я только нашел одна команда онлайн это дало мне ошибку с плохим разделителем.
любая помощь будет высоко ценится! Кто-то наверняка придумает умный однострочный лайнер, но я не специалист по оболочкам.
8 ответов:
comm -23 file1 file2
-23 подавляет строки в обоих файлах, или только в файл 2. Файлы должны быть отсортированы (они находятся в вашем примере) , но если нет, пропустите их через
sort
первый...посмотреть man page здесь
grep -Fvxf <lines-to-remove> <all-lines>
- работает с несортированными файлами
- поддерживает порядок
- это POSIX
пример:
cat <<EOF > A b 1 a 0 01 b 1 EOF cat <<EOF > B 0 1 EOF grep -Fvxf B A
выход:
b a 01 b
объяснение:
-F
: использовать строковые литералы, а не по умолчанию Бре-x
: рассматривайте только совпадения, соответствующие всей строке-v
: принт несоответствие-f file
: возьмите шаблоны из данного файлаэтот метод медленнее на предварительно отсортированных файлах, чем другие методы, так как он является более общим. Если скорость также имеет значение, см.:быстрый способ поиска строк в одном файле, которые не находятся в другом?
Смотрите также: https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another
awk в помощь!
это решение не требует сортировки входных данных. Вы должны предоставить fileB в первую очередь.
awk 'NR==FNR{a[];next} !( in a)' fileB fileA
возвращает
A C
как это работает?
NR==FNR{a[];next}
идиома предназначена для хранения первого файла в ассоциативном массиве в качестве ключей для последующего теста "содержит".
NR==FNR
проверяет, сканируем ли мы первый файл, где глобальный счетчик строк (NR) равен счетчик текущей строки файла (FNR).
a[]
добавляет текущую строку в ассоциативный массив в качестве ключа, обратите внимание, что это ведет себя как набор, где не будет никаких повторяющихся значений (ключей)
!( in a)
теперь мы находимся в следующем файле(ах),in
содержит тест, здесь он проверяет, находится ли текущая строка в наборе, который мы заполнили на первом шаге из первого файла,!
перечеркивает состоянии. Здесь отсутствует действие, которое по умолчанию является{print}
и обычно не написано явно.обратите внимание, что теперь это можно использовать для удаления слов из черного списка.
$ awk '...' badwords allwords > goodwords
С небольшим изменением он может очистить несколько списков и создать очищенные версии.
$ awk 'NR==FNR{a[];next} !( in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
другой способ сделать то же самое (также требует отсортированный вход):
join -v 1 fileA fileB
в Bash, если файлы не предварительно отсортированы:
join -v 1 <(sort fileA) <(sort fileB)
вы можете сделать это, если ваши файлы не отсортированы
diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a
--new-line-format
для строк, которые находятся в файле b, но не в a--old-..
для строк, которые находятся в файле a, но не в b--unchanged-..
для строк, которые находятся в обоих.%L
делает так, что строка печатается точно.man diff
для более подробной информации
это уточнение хорошего ответа @karakfa может быть заметно быстрее для очень больших файлов. Как и в этом ответе, ни один файл не нужно сортировать, но скорость обеспечивается за счет ассоциативных массивов awk. В памяти хранится только файл подстановки.
эта формулировка также допускает возможность использования при сравнении только одного конкретного поля ($N) во входном файле.
# Print lines in the input unless the value in column $N # appears in a lookup file, $LOOKUP; # if $N is 0, then the entire line is used for comparison. awk -v N=$N -v lookup="$LOOKUP" ' BEGIN { while ( getline < lookup ) { dictionary[]= } } !($N in dictionary) {print}'
(еще одним преимуществом этого подхода является то, что его легко изменить критерий сравнения, например, для обрезки переднего и заднего пробелов.)