Є два файли під назвою "a.txt" і "b.txt", обидва мають список слів. Тепер я хочу перевірити, які слова є зайвими в "a.txt", а не в "b.txt" .
Мені потрібен ефективний алгоритм, оскільки мені потрібно порівняти два словники.
Є два файли під назвою "a.txt" і "b.txt", обидва мають список слів. Тепер я хочу перевірити, які слова є зайвими в "a.txt", а не в "b.txt" .
Мені потрібен ефективний алгоритм, оскільки мені потрібно порівняти два словники.
Відповіді:
якщо встановлено vim, спробуйте це:
vimdiff file1 file2
або
vim -d file1 file2
ви знайдете це фантастичним.
Сортуйте їх та використовуйте comm
:
comm -23 <(sort a.txt) <(sort b.txt)
comm
порівнює (сортується) вхідні файли та за замовчуванням виводить три стовпці: рядки, унікальні для a, рядки, унікальні для b, і рядки, які є в обох. Вказавши -1
, -2
і / або -3
ви можете придушити відповідний висновок. Тому comm -23 a b
перераховуються лише записи, які є унікальними для. Я використовую <(...)
синтаксис для сортування файлів під час льоту, якщо вони вже відсортовані, вам цього не потрібно.
comm
є більш ефективним, тому що він виконує роботу за один цикл, не зберігаючи весь файл у пам'яті. Оскільки ви використовуєте словники, які, швидше за все, вже відсортовані, вам навіть не потрібні sort
. Використання grep -f file1 file2
з іншого боку , буде завантажити всю file1
в пам'ять і порівняти кожен рядок в file2
з усіма цими записами, що є набагато менш ефективним. Це в основному корисно для невеликих, несолодких -f file1
.
\n
також буде включено для порівняння.
Ви можете використовувати diff
інструмент в Linux для порівняння двох файлів. Для фільтрації необхідних даних можна використовувати параметри --changed-group та --unchanged-group-format .
Наступні три варіанти можна використовувати для вибору відповідної групи для кожного варіанта:
'% <' отримати рядки з FILE1
'%>' отримати рядки з FILE2
'' (порожній рядок) для видалення рядків з обох файлів.
Напр .: diff --changed-group-format = "% <" --unchanged-group-format = "" file1.txt file2.txt
[root@vmoracle11 tmp]# cat file1.txt
test one
test two
test three
test four
test eight
[root@vmoracle11 tmp]# cat file2.txt
test one
test three
test nine
[root@vmoracle11 tmp]# diff --changed-group-format='%<' --unchanged-group-format='' file1.txt file2.txt
test two
test four
test eight
Якщо ви віддаєте перевагу стилю виводу diff від git diff
, ви можете використовувати його з --no-index
прапором для порівняння файлів, які не знаходяться у сховищі git:
git diff --no-index a.txt b.txt
Використовуючи пару файлів з приблизно 200k рядків імен файлів у кожному, я порівняв (за допомогою вбудованої time
команди) цей підхід проти деяких інших відповідей тут:
git diff --no-index a.txt b.txt
# ~1.2s
comm -23 <(sort a.txt) <(sort b.txt)
# ~0.2s
diff a.txt b.txt
# ~2.6s
sdiff a.txt b.txt
# ~2.7s
vimdiff a.txt b.txt
# ~3.2s
comm
здається, найшвидший на сьогоднішній день git diff --no-index
здається, це найшвидший підхід для виведення різного стилю.
Оновлення 2018-03-25 Правда ви можете фактично опустити --no-index
прапорець, якщо ви не знаходитесь у сховищі git і не хочете порівнювати непотрібні файли у цьому сховищі. З чоловічої сторінки :
Ця форма полягає у порівнянні заданих двох шляхів у файловій системі. Ви можете опустити параметр --no-index при виконанні команди в робочому дереві, керованому Git, і принаймні в одній з точок шляхів поза робочим деревом або при запуску команди поза робочим деревом, керованим Git.
Ви також можете використовувати: colordiff : Відображення виводу з кольорами.
Про vimdiff : Він дозволяє порівнювати файли через SSH, наприклад:
vimdiff /var/log/secure scp://192.168.1.25/var/log/secure
Витягнуто з: http://www.sysadmit.com/2016/05/linux-diferencias-entre-dos-archivos.html
Також не забувайте про mcdiff - внутрішній диспетчер перегляду GNU Midnight Commander .
Наприклад:
mcdiff file1 file2
Насолоджуйтесь!
Використовувати comm -13
(потрібні відсортовані файли) :
$ cat file1
one
two
three
$ cat file2
one
two
three
four
$ comm -13 <(sort file1) <(sort file2)
four
Ось моє рішення для цього:
mkdir temp
mkdir results
cp /usr/share/dict/american-english ~/temp/american-english-dictionary
cp /usr/share/dict/british-english ~/temp/british-english-dictionary
cat ~/temp/american-english-dictionary | wc -l > ~/results/count-american-english-dictionary
cat ~/temp/british-english-dictionary | wc -l > ~/results/count-british-english-dictionary
grep -Fxf ~/temp/american-english-dictionary ~/temp/british-english-dictionary > ~/results/common-english
grep -Fxvf ~/results/common-english ~/temp/american-english-dictionary > ~/results/unique-american-english
grep -Fxvf ~/results/common-english ~/temp/british-english-dictionary > ~/results/unique-british-english
sdiff -s file1 file2
було корисно.
Використання awk для цього. Тестові файли:
$ cat a.txt
one
two
three
four
four
$ cat b.txt
three
two
one
The awk:
$ awk '
NR==FNR { # process b.txt or the first file
seen[$0] # hash words to hash seen
next # next word in b.txt
} # process a.txt or all files after the first
!($0 in seen)' b.txt a.txt # if word is not hashed to seen, output it
Дублікати викреслюються:
four
four
Щоб уникнути дублікатів, додайте в seen
хеш кожне нещодавно зустрінене слово в a.txt :
$ awk '
NR==FNR {
seen[$0]
next
}
!($0 in seen) { # if word is not hashed to seen
seen[$0] # hash unseen a.txt words to seen to avoid duplicates
print # and output it
}' b.txt a.txt
Вихід:
four
Якщо списки слів розділені комами, наприклад:
$ cat a.txt
four,four,three,three,two,one
five,six
$ cat b.txt
one,two,three
вам доведеться зробити кілька додаткових кіл ( for
циклів):
awk -F, ' # comma-separated input
NR==FNR {
for(i=1;i<=NF;i++) # loop all comma-separated fields
seen[$i]
next
}
{
for(i=1;i<=NF;i++)
if(!($i in seen)) {
seen[$i] # this time we buffer output (below):
buffer=buffer (buffer==""?"":",") $i
}
if(buffer!="") { # output unempty buffers after each record in a.txt
print buffer
buffer=""
}
}' b.txt a.txt
Виведіть цей раз:
four
five,six
diff a.txt b.txt
недостатньо?