我希望将 file1与 file2进行比较,并生成一个 file3,其中包含 file1中不在 file2中的行。
Unix 实用程序 diff正是为此而设计的。
diff
$ diff -u file1 file2 > file3
查看手册和互联网的选项,不同的输出格式等。
使用 Diff 实用程序,只提取输出中以 < 开头的行
有时 diff是您需要的实用程序,但有时 join更合适。这些文件需要预先排序,如果您使用的 shell 支持 bash、 ksh 或 zsh 等进程替换,则可以动态进行排序。
join
join -v 1 <(sort file1) <(sort file2)
想想这个: 文件 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中。”
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 支持)。
试试看
sdiff file1 file2
在大多数情况下,这种方法对我来说效果要好得多。 如果行的顺序不重要(例如某些文本配置文件) ,您可能希望先对文件进行排序。
比如说,
sdiff -w 185 file1.cfg file2.cfg
已经有很多答案了,但恕我直言,没有一个是完美的。Thanatos 的答案在每行中留下了一些额外的字符,SorPigal 的答案要求对文件进行排序或预先排序,这在所有情况下可能都不够。
我认为获得不同的行(没有额外的字符,没有重新排序)的最佳方法是 diff、 grep和 awk(或类似的)的组合。
grep
awk
如果行中不包含任何“ <”,则可以使用简短的一行程序:
diff urls.txt* | grep "<" | sed 's/< //g'
但是这将从行中删除“ <”(小于,空格)的每个实例,这并不总是 OK (例如源代码)。最安全的选择是使用 awk:
diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'
这个一行程序区分两个文件,然后过滤掉 diff 的 ed 样式输出,然后删除 diff 添加的尾部“ <”。即使行本身包含一些“ <”,这也是可行的。
如果你需要用核心组件来解决这个问题,公认的答案是好的:
comm -23 <(sort file1) <(sort file2) > file3
您还可以使用 SD(流 diff) ,它不需要排序或进程替换,并且支持无限流,如下所示:
cat file1 | sd 'cat file2' > file3
在这个例子中可能没有那么多好处,但是仍然要考虑它; 在某些情况下,您将不能使用 comm、 grep -F或 diff。
comm
grep -F
下面是我写的关于终端上不同流的 博客文章,它引入了 sd。
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt
在这个帖子里,我试了几乎所有的答案,但没有一个是完整的。经过几次尝试后,我终于成功了。差异会给你一些不同,但与一些不必要的特殊字符。其中实际的差异行以’>’开头。因此,下一步是以“ >”开头的 Grep行,然后用 Sed删除相同的行。
然而,没有 grep解决方案?
只存在于文件2中的行:
grep -Fxvf file1 file2 > file3
只存在于文件1中的行:
grep -Fxvf file2 file1 > file3
两个文件中都存在的行:
grep -Fxf file1 file2 > file3
开关说明(另见 man grep) :
man grep
-F
-x
-f
-v
您可以使用 diff进行以下输出格式设置:
diff --old-line-format='' --unchanged-line-format='' file1 file2
--old-line-format='',如果 file2中的代码行不同,则禁用 file1的输出。 --unchanged-line-format='',禁用输出,如果行是相同的。
--old-line-format=''
--unchanged-line-format=''
我很惊讶没有人向 产生并列输出提到 diff -y,例如:
diff -y
diff -y file1 file2 > file3
在 file3中(不同的行中间有一个符号 |) :
file3
|
same same diff_1 | diff_2
如果您有一个带有 单列甚至多列的 CSV 文件,那么您可以使用 sqlite3嵌入式 db 逐行执行这些“ diff”操作。它附带了 python,所以应该可以在大多数 linux/macs 上使用。您可以在 bash shell 上编写 sqlite3命令脚本,而无需编写 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 都可以。
我尝试过使用内置的 diff 和 comm 工具对多个 GB 文件进行 diff。Sqlite 远远超过 Linux 实用程序。
linecount=0 while IFS= read -r line1; do let linecount=linecount+1 IFS= read -r line2 < $2 if [ "$line1" != "$line2" ] ; then echo "============diff: $linecount" echo "LINE1 $line1"; echo "LINE2 $line2"; echo "" fi done < $1