различать два больших файла CSV (каждый по 90 ГБ) и выводить их в другой csv

О вашей команде:

mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/sda1 /dev/sda2

Вы создаете массив полосового рейда на двух разделах sda1 и sda2. Размер массива raid будет вдвое больше наименьшего размера sda1 и sda2.

Если вы хотите создать полосовой массив raid-0 размером 2 ГБ, вы должны использовать для него n-count дисков или разделов размером 2 ГБ / n. В вашем примере два раздела должны иметь размер 1 ГБ.

Не используйте raid на одном диске в реальных ситуациях, это снизит производительность и безопасность данных.

Чтобы смонтировать файловую систему с помощью метки, используйте эту команду:

mount -t ext4 LABEL=RAID_0 /storage

Для постоянного монтирования:

echo "LABEL=RAID_0 /storage ext4 defaults 0 0" >> /etc/fstab
mount -a
3
13.04.2017, 15:36
3 ответа

Рассмотрим инструменты, которые объединяют два файла построчно:

  • paste объединяет два файла строка за строкой, не обращая внимания на содержимое.
  • comm объединяет отсортированные файлы, обращая внимание на одинаковые строки. Это может отсеять одинаковые строки, но для последующего объединения отличающихся строк потребуется другой инструмент.
  • join объединяет отсортированные файлы, сопоставляя идентичные поля вместе.
  • sort может объединить два файла.
  • awk может объединить несколько файлов в соответствии с любыми правилами, которые вы ему зададите. Но при работе с такими большими файлами вы, скорее всего, получите лучшую производительность, используя наиболее подходящие специализированные инструменты, а не инструменты общего назначения.

Я буду считать, что дубликатов нет, т.е. в одном файле нет двух строк с одинаковыми ID, датой и характеристикой. Если дубликаты есть, то их обработка зависит от того, как вы хотите с ними обращаться. Я также предполагаю, что файлы отсортированы. Я также предполагаю, что ваша оболочка имеет подстановку процессов, например, bash или ksh, а не простой sh, и что у вас есть GNU coreutils (что имеет место в не встроенных Linux и Cygwin).

Я не знаю, какие у вас разделители - пробелы или табуляция. Я предполагаю, что пробелы; если разделитель всегда ровно одна табуляция, то объявление табуляции символом-разделителем (cut -d $'\t', join -t $'\t', sort -t $'\t') и использование \t вместо [ \t]\+ должно немного увеличить производительность.

Установите локаль на чистый ASCII (LC_ALL=C), чтобы избежать любых потерь производительности, связанных с многобайтовыми символами.

Поскольку join может объединять строки только на основе одного поля, нам нужно сделать так, чтобы поля 1-3 отображались как одно поле. Для этого измените разделитель, либо между 1 и 2 и 2 и 3, либо между 3 и 4. Я изменю 1-3, чтобы использовать ; вместо пробелов. Таким образом, вы получите все комбинации строк, независимо от того, идентичны они или нет. Затем вы можете использовать sed для удаления строк с одинаковыми значениями.

join -a 1 -a 2 <(sed 's/[ \t]\+/;/; s/[ \t]\+/;/' file1.csv) <(sed 's/[ \t]\+/;/; s/[ \t]\+/;/' file2.csv) |
sed '/[ \t]\(.*\)[ \t]\+\1$/d' |
tr ';' '\t'

Заметьте, что непарные строки в конечном итоге будут выглядеть как 4-колоночная строка без указания на то, откуда они взяты - из файла 1 или из файла 2. Удалите -a 1 -a 2, чтобы подавить все непарные строки.

Если у вас есть большинство идентичных строк, это тратит время на их объединение и отсев. Другой подход заключается в использовании comm -3 для удаления идентичных строк. В результате получается один выходной поток, в котором строки расположены по порядку, но строки из файла 2 имеют ведущую табуляцию. Затем вы можете использовать awk для объединения последовательных строк, где два файла имеют одинаковые поля 1-3. Поскольку для этого используется awk, он может работать медленнее, если имеется много неидентичных строк.

comm -3 file1.csv file2.csv |
awk '
    $1 "\t" $2 "\t" $3 == k { if ($4 != v) print k "\t" v "\t" $4; next; }
    { print k "\t" v }
    { k=$1 "\t" $2 "\t" $3; v=$4; }
'
3
27.01.2020, 21:21

EDIT: Этот ответ может сработать для тех, у кого в системе около 200 ГБ свободной оперативной памяти. Упс.


diff --side-by-side --suppress-common-lines file1.csv file2.csv

по умолчанию разделяет | и строки шириной 130 символов (при необходимости обертывает). Думаю, это не то же самое, что ваш формат ввода.

Вы можете попробовать что-то вроде

diff --old-line-format="%l$(printf '\t')" --new-line-format="%L" --unchanged-line-format="" file1.csv file2.csv
0
27.01.2020, 21:21

Я нашел способ быстро сравнить 2 файла с 1 миллионом строк. Мне нужно было, чтобы два файла были равны. Команда diff была медленной, но чтобы ускорить ее, просто отсортируйте файлы перед их сравнением.

В общем,:

sort file01.txt > file01_sorted.txt
sort file02.txt > file02_sorted.txt

Затем запустите команду diff:

diff file01_sorted.txt file02_sorted.txt

Или вы также можете выполнить md5sum для отсортированных файлов

md5sum file01_sorted.txt
md5sum file02_sorted.txt
1
15.09.2021, 09:27

Теги

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