Перекрытие / сравнение двух файлов и печать того, что не соответствовало

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

Файл 1:

123.txt
456.txt
789.txt
101112.txt

Файл 2:

123.txt 
789.txt
101112.txt

Есть ли какой-нибудь bash? команда, которую я могу использовать, чтобы перекрывать их и печатать только те строки или имена файлов, которые не совпадают. Поэтому я ожидаю что-то вроде этого:

456.txt
7
задан 15 January 2018 в 12:39

4 ответа

comm ваш друг здесь:

Если файлы уже отсортированы:

comm -3 f1.txt f2.txt

Если не отсортированы, sort и передать их в качестве дескрипторов файлов с использованием процесса замены так что нам не нужны никакие временные файлы):

comm -3 <(sort f1.txt) <(sort f2.txt)

Пример:

% cat f1.txt
123.txt
456.txt
789.txt
101112.txt

% cat f2.txt
123.txt
789.txt
101112.txt

% comm -3 <(sort f1.txt) <(sort f2.txt)
456.txt
13
ответ дан 15 January 2018 в 12:39

Простой подход заключается в использовании двух команд 'grep', каждая из которых принимает один из файлов в виде списка строк для поиска в другом файле. Предполагая, что ваши файлы имеют имена f1.txt и f2.txt:

grep -Fxvf f1.txt f2.txt ; grep -xvf f2.txt f1.txt

Используются следующие параметры grep:

  • -F - Используйте каждую строку в качестве фиксированной строки для сопоставления, а не регулярное выражение
  • -x - Только для совпадения целых строк
  • -v - Инвертируйте совпадение для выбора несовпадающих строк
  • -f - использовать файл, заданный в качестве аргумента, в качестве списка шаблонов для сопоставления
3
ответ дан 15 January 2018 в 12:39

Я понимаю ваш вопрос так, как вы хотите, чтобы все строки появлялись только в одном из файлов, а не в обоих, независимо от порядка строк.

Я также предполагаю, что мы сравниваем файлы f1.txt и f2.txt. Вместо этого введите ваши соответствующие имена.

Используя Bash, вы можете сделать это с двумя циклами, где каждый обрабатывает один файл и проверяет каждую строку, появляется ли она в другой. Этот подход не очень эффективен, но он должен работать:

# This loops over f1.txt and searches each line in f2.txt
while read line ; do grep -Fxqe "$line" f2.txt || echo "$line" ; done < f1.txt 

# This loops over f2.txt and searches each line in f1.txt
while read line ; do grep -Fxqe "$line" f1.txt || echo "$line" ; done < f2.txt 

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

Более точное решение может быть написано, например, с коротким однострочником Python:

python3 -c 's1=set(open("f1.txt")); s2=set(open("f2.txt")); print(*s1.symmetric_difference(s2), sep="")'

При этом используется структура данных Set, которая содержит только уникальные значения и допускает операции над множествами, такие как «симметричная разность».

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

2
ответ дан 15 January 2018 в 12:39

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

cat file1 file2 | sort | uniq -u

Объяснение:

cat file1 file2

Выводит оба файла на стандартный вывод один за другим.

sort

Сортирует объединенное содержимое двух файлов. Полезный побочный эффект, который нас интересует, заключается в том, что он помещает одинаковые строки из обоих файлов рядом друг с другом.

uniq -u

Выводит только строки, которые являются «уникальными», то есть встречаются только один раз. Достаточно досадно, что это смотрит только на пары соседних линий, поэтому необходима предыдущая команда sort.

Вы также можете использовать uniq -d для вывода только тех строк, которые встречаются дважды. Это даст вам строки, общие для обоих файлов.

ПРИМЕЧАНИЕ: Я не уверен, насколько хорошо это решение работает, если одни и те же строки встречаются в одном файле более одного раза.

1
ответ дан 15 January 2018 в 12:39

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

Похожие вопросы: