Проверьте, все ли строки файла находятся в разных файлах


14

Я получил два файла: file1 с примерно 10 000 строк и file2 с несколькими сотнями строк. Я хочу проверить, все ли строки file2 встречаются в file1. То есть: ∀ строка ℓ ∈ файл2: ℓ ∈ файл1

Если кто-то не знает, что означают эти символы или что означает «проверить, все ли строки файла2 встречаются в файле1»: несколько эквивалентных строк в обоих файлах не влияют на то, возвращает ли проверка соответствие файла требованиям или нет.

Как мне это сделать?


2
Могут ли эти файлы иметь повторяющиеся строки? Если file2содержит 2 строки A, нужно file1ли содержать как минимум 2 строки A?
Стефан

2
@ StéphaneChazelas Все строки (в обоих файлах) гарантированно будут уникальными.
UTF-8

1
@ UTF-8 Это была бы важная деталь для редактирования вашего вопроса.
Дэвид Z

2
@ ДавидЗ Больше не существует, поскольку существующие ответы не полагаются на эту гарантию. Таким образом, редактируя вопрос сейчас, я бы уменьшил видимый объем ответов.
UTF-8

@ UTF-8 Полагаю, что так, хотя вопрос без него немного двусмысленный, например, если данная строка встречается 5 раз в файле 2, должна ли эта строка также встречаться 5 раз в файле 1 (а не только один раз)? Если бы у вас было это требование, похоже, что ни один из существующих ответов не сработает, поэтому я бы предложил по крайней мере отредактировать что-то, что даст вам понять, что это не то, что вы имеете в виду.
Дэвид Z

Ответы:


18
comm -13 <(sort -u file_1) <(sort -u file_2)

Эта команда выведет строки, уникальные для file_2. Таким образом, если выходные данные пусты, то все file_2строки содержатся в file_1.

От человека комм:

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

@don_crissti Правда. Исправлено: -uопция добавлена ​​в sortкоманду. Теперь в обоих отсортированных файлах остались только уникальные строки.
MiniMax

Потрясающе простое решение! Применим ли этот синтаксис к любой программе, которая ожидает файлы? Я всегда думал, что по <трубопроводу в стандартный ввод. Меняет ли это скобочный термин?
UTF-8

2
@ UTF-8 Это называется заменой процесса . Вы можете прочитать здесь об этом. И да, он ведет себя как временный файл, поэтому его можно использовать вместо реальных файлов в любых программах, которые ожидают файлы.
MiniMax

Если это то, что вы делаете часто, вы можете сохранить file_1в предварительно отсортированном виде. Экономит как набор текста, так и время.
Стиг Хеммер

7
@minimax Хороший комментарий, кроме «любой». Подстановка процессов, хотя и замечательна, не может использоваться во всех случаях, потому что получающиеся в результате «файлы» являются потоками, а не реальными файлами. Это означает, что они не являются «доступными для поиска», как обычный файл, и могут использоваться только в том случае, если программа читает файл с самого начала в обычном режиме, а не тогда, когда программа использует некоторые функции только для файлов, такие как поиск в определенной точке или перематывать, чтобы начать все сначала. К счастью, большинство программ просто читают () свои файлы, поэтому подстановка процессов работает с большинством программ, но не с «любыми» программами.
Закон 29

7
[ $(grep -cxFf file2 <(sort -u file1)) = $(sort -u file2 | wc -l) ] && 
  echo all there || 
  echo some missing

Если количество совпадений из file2 в (уникальных строках) file1 совпадает с количеством уникальных строк в file2, то все они есть; в противном случае они не.


5

Использование GNU, awkгде он поддерживает определенные length(array)функции (и некоторые другие awkреализации, которые могут поддерживать) и не требуется, если файлы отсортированы.

gawk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{print (!length(seen))?"Matched":"Not Matched"}' file2 file1

Это чтение файла2 в массив, называемый seenключом как целая строка файла2 .

Затем прочитайте file1 и для каждой строки, если она совпадает со строками в массиве, затем удалите этот ключ.

В конце, если массив был пустым, это означает, что все строки в файле2 существуют в файле1 и будут напечатаны Matched, в противном случае будет отображаться Not Matched.


Для совместимости во всех awkреализациях.

awk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{for(x in seen);print (!x)?"Matched":"Not Matched"}' file2 file1

Чтобы игнорировать пустые строки / или строки с пробелами только в случае file2 , вам необходимо добавить NFусловие в, NR==FNR && NF {...чтобы пропустить чтение их в массив.


length(array)AFAIK только для gawk; это определенно не POSIX.
dave_thompson_085

@ dave_thompson_085 Правильно, я обновил свой ответ. спасибо
αғsнιη

3

С помощью commвы можете найти строки, которые являются общими в обоих файлах.

comm -12 file1 file2

Посмотрите на man commболее подробную информацию


Правильно, он возвращает общие строки в обоих файлах, но это не дает ответа на вопрос оператора Q, где, если у вас есть строка в файле2, которая не завершается в файле1, поэтому все строки файла2 не существуют в файле1.
αғsнιη

1
файлы должны быть отсортированы. От человека " comm- сравнить два отсортированных файла построчно".
MiniMax

@MiniMax прав. Это не работает Другой ответ использует commрешение, которое не является явно неправильным. Когда я запускаю вашу команду, я получаю предупреждения о том, что файлы не в порядке сортировки, и много строк, которые определенно есть в обоих файлах.
UTF-8

3
diff -q <(sort -u file2) <(grep -Fxf file2 file1 | sort -u)

не будет производить никакого вывода , если file1содержит все строки в file2и выйти со статусом 0, в противном случае он будет печатать что - то вроде

Files /proc/self/fd/11 and /proc/self/fd/12 differ

и выйти со статусом 1


2

Используйте программу на Python:

#!/usr/bin/env python3
import sys

def open_arg(path):
    return sys.stdin if path == '-' else open(path)

def strip_linebreak(s):
    return s[:-1] if s.endswith('\n') else s

with open_arg(sys.argv[1]) as pattern_file:
    patterns = set(map(strip_linebreak, pattern_file))

with open_arg(sys.argv[2]) as dataset_file:
    for l in map(strip_linebreak, dataset_file):
        patterns.remove(l)
        if not patterns:
            break

sys.exit(int(bool(patterns)))

Использование:

python3 contains-all.py file2 file1

Состояние завершения программы указывает, были ли сопоставлены все шаблоны файла 2:

  • 0 (успех) означает, что все шаблоны были сопоставлены.
  • 1 (сбой) означает, что некоторые шаблоны не были сопоставлены.

Для запроса состояния выхода в оболочке (сценарий) , вы можете использовать либо $?специальные переменные или другие выражения , которые оценивают состояние выхода команды, например , оператор от короткого замыкания &&и ||и условных выражения , как ifили while. Пример:

if python3 compare-all.py file2 file1 && some-other --condition; then
    # do stuff
fi

1

combineиз moreutils покажет вам все строки file2, которые не связаны file1с:

combine file2 not file1

Затем вы можете посчитать количество строк, добавив его wc -l, например:

if [ $(combine file2 not file1 | wc -l) != 0 ]; then
  echo "lines missing"
else
  echo "You're fine"
fi
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.