防止diff在文件末尾检查换行符


21

我有两棵大树,我想比较一下。树中的某些文件有所不同,只是一个文件末尾有换行符,而另一个文件缺少此换行符。我想忽略这个事实。我试过diff像这样打电话:

diff --ignore-all-space -r <dir1> <dir2>

这正在工作。我的问题是,它也忽略了其他差异(与空间相关),这可能很重要。

总结:我只想忽略EOF的换行符。这可能diff吗?

Answers:


17

基本上,您需要比较两个文件,有条件地忽略尾随字节。没有'diff'选项可以执行此操作-但是有很多方法可以完成(例如,十六进制diff也可以想到)。

要使用“ diff”,您基本上必须修改文件末尾缺少换行符的文件,然后进行比较。您可以使用修改后的文件创建一个临时目录,也可以使用少量脚本来在内存中完成。(至于首选,取决于首选项,文件大小,文件数量...)

例如,以下内容将修改文件的内容(用于sed -i就地修改,这只会打印到stdout)以在缺少一个换行符时添加换行符(如果已有换行符,则使文件保持不变):

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以递归方式比较目录。如果比较目录ab,然后在所有文件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

你能解释一下sed -e '$a\'到底是什么吗?THX
törzsmókus

sed给定以下(-e)脚本/表达式(与文件($)的末尾相匹配)的情况下运行run ,并执行“附加”操作(a \),但实际上并未指定任何文本(在\后面)仍将在文件末尾添加EOF /换行符(仅在丢失时)。
迈克尔

谢谢。我还没见过a\ 呢。
törzsmókus

1

我通过在每个文件中添加换行符并忽略diff(选项-B)中的空行来解决该问题。此解决方案可能不适合您的用例,但可能会帮助其他人:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 

0

将输出的管道diff传递给grep命令,该命令会删除您不想看到的消息。


不好。如果我不添加--ignore-all-space,则diff -r存在,结果为!= 0。需要明确的是:我希望diff仅在EOF时忽略EOF的换行符。我希望它报告符合此条件的结果。也就是说,如果在树中的文件的换行符在EOF,即不得被视为差别只不同,因此必须DIFF返回0
dangonfast

0

只是想到了一种不同的方法,该方法也适用于较大的文件(仍然不会复制或修改原始文件)。您仍然必须模拟递归目录遍历(有多种方法可以执行此操作),但是此示例不使用“ 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


0

答案很简单。
关于缺少换行符的消息不在输出流中,diff而是在错误流中。所以把它变成必杀技,你就做好了

diff -rqEeB fileA fileB 2> /dev/null

diff如果发现差异并且我想检查该值,则返回值!= 0。重定向到/ dev / null不会使diff忘记该差异,因此返回的值是!= 0,我不希望这样做。我希望diff如果唯一的区别是最后一个换行符
则将

-1

diff commnad中有一个标志:--strip-trailing-cr可以完全满足您的要求


-1。你有尝试过吗?它/r/n像EOF之前一样对待/n,与多余无关/n
卡米尔Maciorowski

我已经尝试过了,并用它来比较不同dos / unix换行符的文件...不是吗?
dharman '17

问题是仅忽略EOF(文件末尾)处的换行符。
卡米尔Maciorowski
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.