Здравствуйте, у меня есть два файла с некоторыми именами файлов, которые выглядят так:
Файл 1:
123.txt
456.txt
789.txt
101112.txt
Файл 2:
123.txt
789.txt
101112.txt
Есть ли какой-нибудь bash? команда, которую я могу использовать, чтобы перекрывать их и печатать только те строки или имена файлов, которые не совпадают. Поэтому я ожидаю что-то вроде этого:
456.txt
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
Простой подход заключается в использовании двух команд 'grep', каждая из которых принимает один из файлов в виде списка строк для поиска в другом файле. Предполагая, что ваши файлы имеют имена f1.txt и f2.txt:
grep -Fxvf f1.txt f2.txt ; grep -xvf f2.txt f1.txt
Используются следующие параметры grep
:
-F
- Используйте каждую строку в качестве фиксированной строки для сопоставления, а не регулярное выражение -x
- Только для совпадения целых строк -v
- Инвертируйте совпадение для выбора несовпадающих строк -f
- использовать файл, заданный в качестве аргумента, в качестве списка шаблонов для сопоставления Я понимаю ваш вопрос так, как вы хотите, чтобы все строки появлялись только в одном из файлов, а не в обоих, независимо от порядка строк.
Я также предполагаю, что мы сравниваем файлы 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, которая содержит только уникальные значения и допускает операции над множествами, такие как «симметричная разность».
Обратите внимание, что при использовании обоих решений, если какой-либо из файлов содержит повторяющиеся строки, они игнорируются и обрабатываются только как одно вхождение.
Предполагая, что вам не нужно, чтобы результаты оставались в исходном порядке, просто используйте:
cat file1 file2 | sort | uniq -u
cat file1 file2
Выводит оба файла на стандартный вывод один за другим.
sort
Сортирует объединенное содержимое двух файлов. Полезный побочный эффект, который нас интересует, заключается в том, что он помещает одинаковые строки из обоих файлов рядом друг с другом.
uniq -u
Выводит только строки, которые являются «уникальными», то есть встречаются только один раз. Достаточно досадно, что это смотрит только на пары соседних линий, поэтому необходима предыдущая команда sort
.
Вы также можете использовать uniq -d
для вывода только тех строк, которые встречаются дважды. Это даст вам строки, общие для обоих файлов.
ПРИМЕЧАНИЕ: Я не уверен, насколько хорошо это решение работает, если одни и те же строки встречаются в одном файле более одного раза.