У меня есть "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
, но не получилось.
решение1
Похоже на работу для 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
решение2
Использование 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
grep -vFf test2.csv test1.csv
найдёт строки, уникальные только дляtest1.csv
grep -vFf test1.csv test2.csv
найдёт строки, уникальные только дляtest2.csv
Наконец, мы подводим итоги
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
Или просто запустите их одну за другой, поскольку они оба пишут в 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
решение3
Если порядок строк не важен, используйте 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
Поскольку порядок сохранять не нужно, просто:
sort test1.csv test2.csv | uniq -u
sort test1.csv test2.csv
: объединяет и сортируетtest1.csv
иtest2.csv
uniq -u
: печатает только те строки, которые не имеют дубликатов