Я уверен, что однажды нашел команду unix, которая могла печатать общие строки из двух или более файлов, знает ли кто-нибудь ее имя? Это было намного проще, чем diff
.
Команда Unix для поиска строк, общих в двух файлах
Ответ 1
Команда, которую вы ищете, comm
. например: -
comm -12 1.sorted.txt 2.sorted.txt
Здесь:
-1: подавить столбец 1 (строки, уникальные для 1.sorted.txt)
-2: подавить столбец 2 (строки, уникальные для 2.sorted.txt)
Ответ 2
Чтобы легко применить команду comm к несортированным файлам, используйте Bash замену процессов:
$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321
Итак, файлы abc и def имеют одну общую линию, одну с "132". Использование comm в несортированных файлах:
$ comm abc def
123
132
567
132
777
321
$ comm -12 abc def # No output! The common line is not found
$
В последней строке не было выхода, общая строка не была обнаружена.
Теперь используйте отсортированные файлы comm, сортируя файлы с заменой процесса:
$ comm <( sort abc ) <( sort def )
123
132
321
567
777
$ comm -12 <( sort abc ) <( sort def )
132
Теперь мы получили строку 132!
Ответ 3
Может быть, вы имеете в виду comm
?
Сравнение отсортированных файлов FILE1 и FILE2 по строкам.
Без параметров выведите трех столбцов. Колонка 1 содержит строки, уникальные для FILE1, столбец два содержат строки, уникальные для FILE2 и три столбца содержат строки, общие для обоих файлов.
Секрет в поиске этой информации - это информационные страницы. Для программ GNU они гораздо более подробные, чем их man-страницы. Попробуйте info coreutils
, и он перечислит вам все полезные полезные утилиты.
Ответ 4
Чтобы дополнить однострочный Perl, здесь его эквивалент awk
:
awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2
Это будет читать все строки из file1
в массив arr[]
, а затем проверить каждую строку в file2
, если она уже существует в массиве (т.е. file1
). Найденные строки будут напечатаны в том порядке, в котором они отображаются в file2
.
Обратите внимание, что сравнение in arr
использует всю строку из file2
в качестве индекса для массива, поэтому оно будет сообщать только точные совпадения на всех строках.
Ответ 5
Пока
grep -v -f 1.txt 2.txt > 3.txt
дает вам разницу в двух файлах (что находится в 2.txt, а не в 1.txt), вы можете легко выполнить
grep -f 1.txt 2.txt > 3.txt
собрать все общие строки, которые должны обеспечить легкое решение вашей проблемы. Если вы отсортировали файлы, вы должны взять comm
, тем не менее. Привет!
Ответ 6
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
Ответ 7
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2
Ответ 8
Если эти два файла еще не отсортированы, вы можете использовать:
comm -12 <(sort a.txt) <(sort b.txt)
и он будет работать, избегая сообщения об ошибке comm: file 2 is not in sorted order
при выполнении comm -12 a.txt b.txt
.
Ответ 9
На ограниченной версии Linux (например, QNAP (nas), над которой я работал):
- комм не существовало
-
grep -f file1 file2
может вызвать некоторые проблемы, как говорит @ChristopherSchultz, и использованиеgrep -f -f file1 file2
было очень медленным (более 5 минут - не завершено - более 2-3 секунд с помощью метода ниже для файлов более 20 МБ)
Итак, вот что я сделал:
sort file1 > file1.sorted
sort file2 > file2.sorted
diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted
Если files.same.sorted
должен быть в том же порядке, что и исходные, то добавьте эту строку для того же порядка, что и file1:
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same
или для того же порядка, что и file2:
awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same
Ответ 10
Просто для справки, если кто-то все еще смотрит, как это сделать для нескольких файлов, см. связанный ответ Поиск совпадающих строк по многим файлам.
Объединив эти два ответа (ans1 и ans2), я думаю, вы можете получить результат, который вы не требуя сортировки файлов:
#!/bin/bash
ans="matching_lines"
for file1 in *
do
for file2 in *
do
if [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
echo "Comparing: $file1 $file2 ..." >> $ans
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
fi
done
done
Просто сохраните его, дайте ему права выполнения (chmod +x compareFiles.sh
) и запустите его. Он примет все файлы, присутствующие в текущем рабочем каталоге, и сделает сравнение all-vs-all, оставив в файле match_lines результат.
Что нужно улучшить:
- Пропустить каталоги
- Избегайте сравнения всех файлов два раза (file1 vs file2 и file2 vs file1).
- Возможно, добавьте номер строки рядом с соответствующей строкой
Ответ 11
rm file3.txt
cat file1.out | while read line1
do
cat file2.out | while read line2
do
if [[ $line1 == $line2 ]]; then
echo $line1 >>file3.out
fi
done
done
Это должно сделать это.