8 ответов:
grep -v -x -f f2 f1следует сделать трюк.объяснение:
-vдля выбора несоответствующих строк-xчтобы соответствовать только целые строки-f f2чтобы получить шаблоны отf2вместо этого можно использовать
-F f2в матче фиксированных строк Сf2, а не шаблоны (в случае, если вы хотите удалить строки в "то, что вы видите, если то, что вы получаете", а не лечение строки вf2в качестве шаблонов regex).
для исключения файлов, которые не слишком велики, вы можете использовать ассоциативные массивы AWK.
awk 'NR == FNR { list[tolower()]=1; next } { if (! list[tolower()]) print }' exclude-these.txt from-this.txtвывод будет в том же порядке, что и "от-этого".txt-файл. Элемент
tolower()функция делает его нечувствительным к регистру, если вам это нужно.алгоритмическая сложность, вероятно, будет O(n) (exclude-these.размер txt) + O (n) (из-за этого.тхт размер)
похоже на ответ Денниса Уильямсона (в основном синтаксические изменения, например, установка номера файла явно вместо
NR == FNRтрюк):
awk '{if (f==1) { r[] } else if (! ( in r)) { print } } ' f=1 exclude-these.txt f=2 from-this.txtссылке
r[]создает запись для этой строки, не нужно устанавливать значение.предполагая, что awk использует хэш-таблицу с постоянным поиском и(в среднем) постоянным временем обновления, временная сложность этого будет O (n + m), где n и m-длины файлов. В моем случае n было ~25 миллионов и м ~14000. Решение awk было намного быстрее, чем сортировка, и я также предпочел сохранить исходный порядок.
если у вас есть Ruby (1.9+)
#!/usr/bin/env ruby b=File.read("file2").split open("file1").each do |x| x.chomp! puts x if !b.include?(x) endкоторый имеет O (N^2) сложность. Если вы хотите заботиться о производительности, вот еще одна версия
b=File.read("file2").split a=File.read("file1").split (a-b).each {|x| puts x}который использует хэш для вычитания, так что сложность O (n) (размер a) + O (n) (размер b)
вот небольшой тест, любезно предоставленный user576875, но с линиями 100K, из вышеперечисленного:
$ for i in $(seq 1 100000); do echo "$i"; done|sort --random-sort > file1 $ for i in $(seq 1 2 100000); do echo "$i"; done|sort --random-sort > file2 $ time ruby test.rb > ruby.test real 0m0.639s user 0m0.554s sys 0m0.021s $time sort file1 file2|uniq -u > sort.test real 0m2.311s user 0m1.959s sys 0m0.040s $ diff <(sort -n ruby.test) <(sort -n sort.test) $
diffбыл использован, чтобы показать, что нет никаких различий между 2 файлами, созданных.
некоторые сравнения времени между различными другими ответами:
$ for n in {1..10000}; do echo $RANDOM; done > f1 $ for n in {1..10000}; do echo $RANDOM; done > f2 $ time comm -23 <(sort f1) <(sort f2) > /dev/null real 0m0.019s user 0m0.023s sys 0m0.012s $ time ruby -e 'puts File.readlines("f1") - File.readlines("f2")' > /dev/null real 0m0.026s user 0m0.018s sys 0m0.007s $ time grep -xvf f2 f1 > /dev/null real 0m43.197s user 0m43.155s sys 0m0.040s
sort f1 f2 | uniq -uдаже не симметричная разность, потому что она удаляет строки, которые появляются несколько раз в файле.comm также может использоваться с stdin и здесь строки:
echo $'a\nb' | comm -23 <(sort) <(sort <<< $'c\nb') # a
Кажется, это работа, подходящая для оболочки SQLite:
create table file1(line text); create index if1 on file1(line ASC); create table file2(line text); create index if2 on file2(line ASC); -- comment: if you have | in your files then specify “ .separator ××any_improbable_string×× ” .import 'file1.txt' file1 .import 'file2.txt' file2 .output result.txt select * from file2 where line not in (select line from file1); .q
ты этой С помощью sed?
sed 's#^#sed -i '"'"'s%#g' f2 > f2.sh sed -i 's#$#%%g'"'"' f1#g' f2.sh sed -i '1i#!/bin/bash' f2.sh sh f2.sh
Comments