逐行比较两个文件并在另一个文件中生成差异

时间:2010-12-28 08:32:33

标签: shell unix

我想将file1与file2进行比较,并生成一个file3,其中包含file1中不存在于file2中的行。

13 个答案:

答案 0 :(得分:194)

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

前提是你的shell支持进程替换(bash)。

答案 1 :(得分:44)

Unix实用程序diff就是为了这个目的。

$ diff -u file1 file2 > file3

有关选项,不同输出格式等,请参阅手册和Internet。

答案 2 :(得分:20)

考虑一下:
文件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

这将回答你的问题:

  

&#34; ...包含file1中的行   不存在于file2中。&#34;

答案 3 :(得分:7)

有时diff是您需要的实用程序,但有时候join更合适。这些文件需要预先排序,或者如果你使用的是支持进程替换的shell,比如bash,ksh或zsh,你可以动态地进行排序。

join -v 1 <(sort file1) <(sort file2)

答案 4 :(得分:5)

尝试

sdiff file1 file2

在大多数情况下,对我来说通常效果更好。 如果行的顺序不重要(例如某些文本配置文件),您可能希望先排序文件。

例如,

sdiff -w 185 file1.cfg file2.cfg

答案 5 :(得分:3)

如果你需要使用coreutils来解决这个问题,那么接受的答案是好的:

comm -23 <(sort file1) <(sort file2) > file3

您还可以使用sd(流差异),它不需要排序或处理替换并支持无限流,如下所示:

cat file1 | sd 'cat file2' > file3

在这个例子中可能没有那么多的好处,但仍然考虑它;在某些情况下,您将无法使用commgrep -Fdiff

这是我写的关于在终端上传播流的blogpost,它引入了sd。

答案 6 :(得分:2)

已经有很多答案,但没有一个完美恕我直言。 Thanatos的回答每行留下一些额外的字符,而Sorpigal的回答要求对文件进行排序或预先排序,这在所有情况下可能都不够。

我认为获得不同的线条的最好方法是没有其他(没有额外的字符,没有重新排序)是diffgrepawk的组合(或类似的)。

如果这些行不包含任何“&lt;”,则短单行可以是:

diff urls.txt* | grep "<" | sed 's/< //g'

但是这将从行中删除“&lt;”(小于空格)的每个实例,这并不总是正常的(例如源代码)。最安全的选择是使用awk:

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'

这个单行文件对两个文件进行区分,然后过滤出diff的ed样式输出,然后删除尾随的“&lt;”差异增加了。即使行包含一些“&lt;”,这也可以工作他们自己。

答案 7 :(得分:1)

使用Diff实用程序并仅提取以&lt;开头的行。在输出中

答案 8 :(得分:1)

diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

我在这个帖子中尝试了几乎所有的答案,但都没有完成。经过几条路径,一条路为我工作。 差异会给你带来不同但有一些不必要的特殊字符。实际差异线以&#39;&gt;开头的地方&#39 ;.所以下一步是 grep 行以&#39;&gt;开头&#39;然后使用 sed 删除相同内容。

答案 9 :(得分:0)

还没有grep解决方案吗?

    仅在file2中存在的
  • 行:

    grep -Fxvf file1 file2 > file3
    
  • 仅在file1中存在的
  • 行:

    grep -Fxvf file2 file1 > file3
    
  • 两个文件中都存在的
  • 行:

    grep -Fxf file1 file2 > file3
    

答案 10 :(得分:0)

您可以将diff用于以下输出格式:

diff --old-line-format='' --unchanged-line-format='' file1 file2

--old-line-format='',如果file2中的行不同,则禁用file1的输出。
--unchanged-line-format='',如果行相同则禁用输出。

答案 11 :(得分:0)

我很惊讶没有人提到diff -y产生并排输出,例如:

diff -y file1 file2 > file3

file3中(不同的行中间有符号|

same     same
diff_1 | diff_2

答案 12 :(得分:0)

如果您的CSV文件具有单列甚至多列,则可以使用sqlite3嵌入式数据库逐行执行“ diff”操作。它带有python,因此应该在大多数linux / macs上可用。您可以在bash shell上编写sqlite3命令的脚本,而无需编写python。

  1. 创建您的a.csv和b.csv文件
  2. 使用命令“ sqlite3 -help”确保安装了sqlite3
  3. 直接在Linux / Mac shell上运行以下命令(或将其放入脚本中)
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命令都有一个换行符

工作原理

  1. 将2个csv分别导入“ atable”和“ btable”。
  2. 使用“ 除外” sql运算符选择“可用”中可用的数据,但选择“稳定表”中的数据。使用选择查询语句创建“结果”表
  3. 通过运行“从结果中选择*”将结果表输出到result.csv。

如果需要对特定列进行操作,则可以使用sqlite3或任何数据库。

我尝试使用内置的diff和comm工具对多个GB文件进行比较。 Sqlite击败了Linux实用程序。