Я хочу сравнить файл1 с файлом2 и создать файл3, содержащий строки в файле1, которых нет в файле2.
Я хочу сравнить файл1 с файлом2 и создать файл3, содержащий строки в файле1, которых нет в файле2.
Ответы:
diff (1) - это не ответ, но comm (1) - это ответ.
NAME
comm - compare two sorted files line by line
SYNOPSIS
comm [OPTION]... FILE1 FILE2
...
-1 suppress lines unique to FILE1
-2 suppress lines unique to FILE2
-3 suppress lines that appear in both files
Так
comm -2 -3 file1 file2 > file3
Входные файлы необходимо отсортировать. Если это не так, сначала отсортируйте их. Это можно сделать с помощью временного файла или ...
comm -2 -3 <(sort file1) <(sort file2) > file3
при условии, что ваша оболочка поддерживает подстановку процессов (bash поддерживает).
comm -23
Утилита Unix diff
предназначена именно для этой цели.
$ diff -u file1 file2 > file3
См. Руководство и Интернет для получения информации о вариантах, различных форматах вывода и т. Д.
Рассмотрим это:
файл a.txt:
abcd
efgh
файл b.txt:
abcd
Вы можете найти разницу с:
diff -a --suppress-common-lines -y a.txt b.txt
Результат будет:
efgh
Вы можете перенаправить вывод в выходной файл (c.txt), используя:
diff -a --suppress-common-lines -y a.txt b.txt > c.txt
Это ответит на ваш вопрос:
"... который содержит строки в файле1, которых нет в файле2."
-d
, что сделает diff
все возможное, чтобы найти наименьшее возможное различие. -i
, -E
, -w
, -B
И --suppress-blank-empty
также может быть полезно время от времени, хотя и не всегда. Если вы не знаете, что подходит вашему варианту использования, попробуйте diff --help
сначала (что обычно является хорошей идеей, если вы не знаете, что может делать команда).
Иногда diff
это именно та утилита, которая вам нужна, но иногда join
более подходящая. Файлы должны быть предварительно отсортированы или, если вы используете оболочку, которая поддерживает подстановку процессов, такую как bash, ksh или zsh, вы можете выполнять сортировку на лету.
join -v 1 <(sort file1) <(sort file2)
Пытаться
sdiff file1 file2
У меня это обычно работает намного лучше в большинстве случаев. Вы можете предварительно отсортировать файлы, если порядок строк не важен (например, некоторые текстовые файлы конфигурации).
Например,
sdiff -w 185 file1.cfg file2.cfg
sdiff <(sort file1) <(sort file2)
)
Если вам нужно решить эту проблему с помощью coreutils, принятый ответ хорош:
comm -23 <(sort file1) <(sort file2) > file3
Вы также можете использовать sd (stream diff), который не требует сортировки или подстановки процессов и поддерживает бесконечные потоки, например:
cat file1 | sd 'cat file2' > file3
Возможно, не так много пользы в этом примере, но все же учтите это; в некоторых случаях вы не сможете использовать comm
ни grep -F
ни diff
.
Вот пост в блоге, который я написал о различиях между потоками на терминале, который представляет sd.
Уже много ответов, но ИМХО ни один из них не идеален. Ответ Танатоса оставляет несколько дополнительных символов в строке, а ответ Сорпигала требует, чтобы файлы были отсортированы или предварительно отсортированы, что может быть неадекватным во всех обстоятельствах.
Я думаю , что лучший способ получения линий , которые не отличаются , и больше ничего (никаких дополнительных символов, без повторного заказа) представляет собой комбинацию diff
, grep
и awk
(или аналогичный).
Если в строках нет символа «<», коротким однострочником может быть:
diff urls.txt* | grep "<" | sed 's/< //g'
но это удалит все экземпляры «<» (меньше, чем пробел) из строк, что не всегда нормально (например, исходный код). Самый безопасный вариант - использовать awk:
diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'
Этот однострочник сравнивает оба файла, затем отфильтровывает вывод diff в стиле ed, а затем удаляет завершающий "<", который добавляет diff. Это работает, даже если в самих строках есть «<».
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt
Я перепробовал почти все ответы в этой теме, но ни один из них не был полным. После нескольких трасс выше один работал у меня. diff даст вам разницу, но с некоторыми нежелательными специальными характеристиками. где ваши фактические разностные линии начинаются с '>'. так что следующий шаг - строки grep начинаются с '>', а затем удаляются с помощью sed .
<
. Вы увидите это, если поменяете порядок входных файлов. Даже если бы вы сделали это, вы бы предпочли опустить grep
, используя больше sed: `diff a1 a2 | sed '/> / s ///' `Это может привести к разрыву строк, содержащих >
или <
в правильной ситуации, и по- прежнему оставлять лишние строки, описывающие номера строк. Если вы хотите попробовать этот подход лучше всего было бы: diff -C0 a1 a2 | sed -ne '/^[+-] /s/^..//p'
.
Вы можете использовать diff
следующее форматирование вывода:
diff --old-line-format='' --unchanged-line-format='' file1 file2
--old-line-format=''
, отключите вывод для файла1, если строка отличается от сравнения в файле2.
--unchanged-line-format=''
, отключите вывод, если строки совпадают.
Если у вас есть файл CSV с одним или даже несколькими столбцами , вы можете выполнять эти построчные операции «diff», используя встроенную базу данных sqlite3. Он поставляется с питоном, поэтому должен быть доступен на большинстве Linux / Mac. Вы можете создать сценарий команд sqlite3 в оболочке bash без необходимости писать python.
echo "
.mode csv
.import a.csv atable
.import b.csv btable
create table result as select * from atable EXCEPT select * from btable;
.output result.csv
select * from result ;
.quit
" | sqlite3 temp.db
Примечание: Убедитесь , что существует новая строка для каждой из команд sqlite3.
Как это устроено
Если вам нужно работать с конкретными столбцами, вам подойдет sqlite3 или любой db.
Я пробовал различать несколько файлов GB, используя встроенные инструменты diff и comm. Sqlite на милю превосходит утилиты Linux.