我有两棵大树,我想比较它们。树中的一些文件不同,只是因为一个文件末尾有换行符,而另一个文件缺少这个换行符。我想忽略这个事实。我试过diff
这样调用:
diff --ignore-all-space -r <dir1> <dir2>
这是可行的。我的问题是它还忽略了其他可能很重要的差异(与空间相关)。
总结一下:我只是想要忽略 EOF 处的换行符。使用 可以实现吗diff
?
答案1
您基本上需要比较两个文件,有条件地忽略尾随字节。没有“diff”选项可以执行此操作 - 但有很多方法可以做到这一点(例如,十六进制 diff 也浮现在脑海中。)
要使用“diff”,您基本上必须修改文件末尾缺少换行符的文件,然后进行比较。您可以创建一个包含修改后文件的临时目录,或者使用一些脚本在内存中完成。(至于首选哪种方法取决于偏好、文件大小、文件数量……)
例如,下面将修改文件的内容(用于sed -i
就地修改,这只会打印到标准输出)以在缺少换行符时添加换行符(如果已经有换行符,则保持不变):
sed -e '$a\' file1.txt
回顾一下“diff”语法(返回 true 表示它们相同,返回 false 表示不同):
$ diff a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different
验证只有空格不同:
$ diff --ignore-all-space a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
** are same
在 bash 中,我们可以使用“sed”来操作文件内容,因为它被传递给“diff”(原始文件保持不变):
$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
&& echo '** are same' || echo '** are different'
** are same
现在您要做的就是diff -r
模拟递归比较目录。如果比较目录a
和b
,则对于a
(例如)中的所有文件,导出(例如)a/dir1/dir2/file.txt
中的文件路径并进行比较:b
b/dir1/dir2/file.txt
$ for f in $( find a -type f )
> do
> diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done
稍微详细一点的版本:
$ for f in $( find a -type f )
> do
> f1=$f
> f2=b/${f#*/}
> echo "compare: $f1 $f2"
> diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
> && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same
答案2
我通过在每个文件中添加换行符并忽略 diff 中的空行(选项-B
)解决了该问题。此解决方案可能不适合你的用例,但可能对其他人有所帮助:
echo >> $FILE1
echo >> $FILE2
diff -B $FILE1 FILE2
答案3
在 Google 上搜索时,一个旧帖子竟然出现在搜索结果的首位,这很不寻常suppress no newline at end of file while diff
。更令人惊讶的是,在浏览完所有回复后,似乎 11 年来这个问题都没有明确的答案!
因此,我决定尝试不同的方法并运行命令diff --help|grep trail
。它显示
-Z, --ignore-trailing-space ignore white space at line end
它有效,而且我猜,当比较位于多个嵌套目录中的代码批次时,这可能会很有帮助。
答案4
我也想到了一种不同的方法,它适用于较大的文件(并且仍然不会复制或修改原始文件)。您仍然必须模拟递归目录遍历(并且有很多方法可以做到这一点),但此示例不使用“sed”,而是仅比较两个文件(不包括最后一个字节),例如cmp
,
$ cmp a/file1.txt b/file1.txt && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different
$ du -b a/file1.txt b/file1.txt
13 a/file1.txt
12 b/file1.txt
$ cmp -n 12 a/file1.txt b/file1.txt && echo '** are same' || echo '** are different'
** are same
仍然循环遍历目录中的所有文件,对于两个文件 a/file.txt 和 b/file.txt,计算较大的文件大小并减一,然后cmp
使用这个字节数执行二进制差异()(也在 bash 中):
(( bytes = $(du -b a/file.txt b/file.txt | sort -nr | head -1 | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt
sed
循环遍历文件与使用和 的其他答案相同diff
。