Различие двух больших файлов

У меня есть "test1.csv", и он содержит

200,400,600,800
100,300,500,700
50,25,125,310

и test2.csv и это содержат

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

теперь

diff test2.csv test1.csv > result.csv

отличается, чем

diff test1.csv test2.csv > result.csv

Я не знаю, который является правильным порядком, но я хочу что-то еще, обе из команд выше произведут что-то как

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

Я хочу произвести только различие, таким образом results.csv должен быть похожим на это

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Я попробовал diff -q и diff -s но они не добивались цели. Порядок не имеет значения, что имеет значение, то, что я хочу видеть только различие, нет>, ни <ни пробел.

grep -FvF добился цели на меньших файлах не на больших

первый файл содержит больше чем 5 миллионов строк, второй файл содержит 1300.

таким образом, results.csv должен привести к ~4 998 700 строкам

Я также попробовал grep -F -x -v -f который не работал.

14
задан 23 June 2015 в 15:27

5 ответов

Походит на задание для comm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

, Как объяснено в man comm:

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

Так, -3 средства, что только строки, которые уникальны для одного из файлов, будут распечатаны. Однако те располагаются с отступом, согласно которому файлу они были найдены в. Для удаления вкладки используйте:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

В этом случае, Вы не должны действительно даже сортировать файлы, и можно упростить вышеупомянутое до:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv
20
ответ дан 23 November 2019 в 02:54

Так как порядок не должен быть сохранен, просто:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: слияния и виды test1.csv и test2.csv
  • uniq -u: печать только строки, которые не имеют никакого дубликата
3
ответ дан 23 November 2019 в 02:54

Используя grep с bash замена процесса:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Сохранить вывод как results.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <() bash шаблон замены процесса

  • grep -vFf test2.csv test1.csv найдет строки уникальными для только test1.csv

  • grep -vFf test1.csv test2.csv найдет строки уникальными для только test2.csv

  • Наконец мы подводим итог результатов cat

Или как предложенный Oli, можно использовать команду, группирующуюся также:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Или просто выполненный один за другим, поскольку они оба пишут в STDOUT, что будут в конечном счете добавлены:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5
6
ответ дан 23 November 2019 в 02:54

Если порядок строк не релевантен, использовать awk или perl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

Использовать grep получить общие строки и фильтровать их:

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

Внутренний grep получает общие строки, затем внешний grep находит строки, которые не соответствуют этим общим строкам.

4
ответ дан 23 November 2019 в 02:54

Используйте --*-line-format=... опции diff

Можно сказать diff точно, в чем Вы нуждаетесь - объясненный ниже:

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt

Возможно указать вывод разности очень подробным способом, подобным a printf числовой формат.

Строки из первого файла, test1.csv названы "старыми" строками и строками от второго, test2.csv, "новые" строки. Это имеет смысл когда diff используется для наблюдения то, что изменилось в файле.

Опции, в которых мы нуждаемся, являются теми для установки формата для "старых" строк, "новых" строк и "неизменных" строк.
Форматы, в которых мы нуждаемся, очень просты:
Для измененных строк, новых и старых, мы хотим произвести только текст строк. %L символ формата для текста строки.
Для неизменных строк мы хотим ничего не показать.

С этим мы можем записать опции как --old-line-format='%L', и соединенный все это, с помощью данных в качестве примера:

$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5


Примечания по производительности

Поскольку файлы имеют другой размер, попытайтесь обмениваться входными файлами, если он не имеет значения, могло бы случиться так что внутренние работы diff может обработать один путь лучше, чем другой. Лучше или нуждается в меньшей памяти или меньшем количестве вычисления.

Существует опция оптимизации для использования diff с большими файлами: --speed-large-files. Это использует предположения о файловой структуре, таким образом, не ясно, помогает ли это в Вашем случае, но стоящий попытки его.

Параметры формата описаны в man diff под --LTYPE-line-format=LFMT.

4
ответ дан 23 November 2019 в 02:54

Другие вопросы по тегам:

Похожие вопросы: