Команда Unix для поиска общих строк в двух файлах
Я уверен, что однажды нашел команду unix, которая могла печатать общие строки из двух или более файлов, кто-нибудь знает ее имя? Это было гораздо проще, чем diff
.
11 ответов
команда, которую вы ищете, это comm
. например:-
comm -12 1.sorted.txt 2.sorted.txt
здесь:
-1: подавить столбец 1 (строки, уникальные для 1.сортированный.txt)
-2 : подавить графе 2 (строки, уникальные для 2.сортированный.txt)
легко применить comm до несортированный файлы, использовать Баша подмена процесса:
$ 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!
может быть, вы имеете в виду comm
?
сравнение отсортированных файлов FILE1 и FILE2 строка за строкой.
без вариантов, произведите выход 3-столбца. Колонки содержит строки, уникальные для FILE1, column два содержит строки, уникальные для FILE2, а третий столбец содержит строки, общие для обоих файлов.
секрет в поиске этой информации-информационные страницы. Для программ GNU они гораздо более детализированы, чем их man-страницы. Попробуй!--1--> и он перечислит вам все мелкие полезные утилиты.
чтобы дополнить Perl one-liner, вот его awk
эквивалентны:
awk 'NR==FNR{arr[];next} in arr' file1 file2
это будет читать все строки file1
в массиве arr[]
, а затем проверьте каждую строку в file2
если он уже существует в массиве (т. е. file1
). Найденные строки будут напечатаны в том порядке, в котором они отображаются в file2
.
Обратите внимание, что сравнение in arr
использует всю строку с file2
как индекс массива, поэтому он будет сообщать только о точных совпадениях по всему русло.
пока
grep -v -f 1.txt 2.txt > 3.txt
дает вам различия двух файлов (что в 2.txt, а не в 1.txt), вы можете легко сделать
grep -f 1.txt 2.txt > 3.txt
собрать все общие линии, которые должны обеспечить легкое решение вашей проблемы. Если вы отсортировали файлы, вы должны взять comm
тем не менее. Привет!
в ограниченной версии Linux (например, QNAP (nas), над которым я работал):
- связи не существовало!--6-->
- 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
если "файлов.тот же.сортировка " должна быть в том же порядке, что и исходные, чем добавить эту строку для того же порядка, чем файл1 :
awk 'FNR==NR {a[]=; next}; in a {print a[]}' files.same.sorted file1 > files.same
или, для того же порядка, что и file2:
awk 'FNR==NR {a[]=; next}; in a {print a[]}' files.same.sorted file2 > files.same
Если два файла еще не отсортированы, вы можете использовать:
comm -12 <(sort a.txt) <(sort b.txt)
и он будет работать, избегая сообщения об ошибке comm: file 2 is not in sorted order
при выполнении comm -12 a.txt b.txt
.
просто для справки если кто-то все еще ищет, как это сделать для нескольких файлов, см. связанный ответ на Поиск совпадающих строк во многих файлах.
сочетание этих двух ответов (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, оставив в файле "matching_lines" результат.
вещи, которые нужно улучшить:
- показывать
- избегайте сравнения всех файлов два раза (file1 vs file2 и file2 vs file1).
- возможно, добавьте номер строки рядом с соответствующей строкой
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
это должно помочь.