无行尾差异的差异比较?

22
我正在使用Mac,处理一些相当老的文件。不同的程序创建了不同的文件,因此其中一些以\r(Mac)结尾,另一些以\n(Unix)结尾。我希望能够在这些文件上运行像diff、grep等命令,但是那些有\r的文件被视为一个巨大的行。是否有diffgrep等版本可以正确处理所有换行符?
预计完成时间:我还希望它们是Unix实用程序,这样我就可以在脚本、Emacs等中使用它们...
7个回答

12
如果你使用diff -w命令,它将忽略文件中的空格,这可能已经足够满足你的需求。
编辑:我刚才发现我第一次误读了帖子,你实际上是在寻找可以处理\r行尾符的diff工具。我的建议是使用像flip这样的工具将文件转换为\n标准格式。
编辑2:我刚刚找到了一个看起来与你想要的类似的工具-Diff'nPatch

Diff'nPatch是GNU 'diff'、'patch'和'cmp'实用程序的Macintosh版本。它可以让你比较和查找两个文件或文件夹之间的差异,整理两个文件,生成各种格式的差异(正常、上下文、unidiff等),应用补丁,按字节比较文件。它可以处理任何类型的行尾符(mac、unix或windows)。


1
不行。 -w 只忽略行内的空格,然后将带有 \r 的文件视为一行,但不包括 \r。而带有 \n 的文件仍然是多行的。 - Brian Postow
似乎Diff'nPatch的链接现在是http://download.cnet.com/Diff-npatch/3000-2247_4-36909.html。 - yanjost
1
我同意Chris的观点:我刚看到Jay的回复。我也遇到了不同行尾的问题,导致diff将文件中的每一行都标记为差异。我比较了DOS/*X文件,使用diff -uw命令解决了这个问题。 - rplantiko
3
对于许多其他程序而言,换行符也是空格字符之一,但diff是一个面向行的程序,换行符始终会结束一行。因此,-w或--ignore-all-space选项不会忽略与换行相关的更改;它只会忽略其他空格更改。 - JobHunter69

9

正如Jay所说,Diff'nPatch似乎是你正在寻找的。或者你可以使用以下单个命令将所有'\r'行结尾转换为'\n':

sed -ie 's/\r/\n/' filename

或者
find . | xargs -n1 sed -ie 's/\r/\n/'

(在后一种情况下,您可能希望以某种方式过滤文件列表,否则它将应用于所有子目录中的所有文件。)

如果他有任何带有Windows风格的\r\n文件,那么这将用\n\n替换每个Windows换行符,这可能不是期望的效果。 - Jay
是的,但我考虑到他只提到了Mac和Unix风格的行尾符... - UncleZeiv
1
不,这些都是苹果电脑,而且我已经有一个非常类似的mac2unix(使用tr而不是sed,但是...)了。 - Brian Postow
请注意,这是一篇旧帖子。我必须在您的第一个命令中添加'g',因为我发现多了一个回车符。即sed -ie 's/\r/\n/g' filename可以产生所需的结果,而sed -ie 's/\r/\n/' filename会在每行后插入一个回车符。我不确定这个额外字符的意义是什么,但对我来说它起作用了。 - LRP

8

OS X v10.7 (Lion) 附带的 diff 工具有一个选项 'strip-trailing-cr',可以实现你想要的功能。使用方法如下:

diff -cpt a.c b.c --strip-trailing-cr

该选项在Linux上也是可用的。 - kenorb
1
它将从diff的输出中删除“cr”,而不是输入。 - Motti Shneor
man页面上说:“在输入时去除尾随回车符。” - Joshua Nozzi

3
PhpStorm的差异视图中的“忽略空格”功能非常好用,它会自动忽略回车符、行尾符等差异。你可以浪费时间去折腾晦涩难懂的Unix命令,或者你可以选择一个真正好用的工具,让生活更美好。
在OS X v10.8(Mountain Lion)上,使用上述任何解决方案都失败了(包括标记为正确答案的解决方案)。所有“Diff-npatch”的下载链接都失效了。(我找到了http://webperso.easyconnect.fr/bdesgraupes/tools.html,但我真的不喜欢不得不使用无法从命令行调用的diff工具,因此无法与我使用的任何IDE或版本控制系统工具集成,例如BBEditSourcetree或SmartSVN-所有这些工具的内置diff工具都无法忽略换行符。

是的,我的换行符是\r,但那又怎样?啊!如果软件太愚蠢以至于无法意识到\r == \n,那我就要使用不同的软件,这些软件足够聪明。

PhpStorm是唯一一个拥有“即插即用”差异工具的软件,这正是我期望Mac软件做到的。我期望Mac软件能够“即插即用”。我使用Mac,这样我就可以专注于工作,而不是在每个转折点学习晦涩的终端命令,这些命令几乎都没有很好的文档说明,只是期望你理解命令应该如何格式化,没有清晰的示例,所以你永远不知道自己是否做错了或者命令是否根本无法工作,就像所有其他糟糕的软件一样。

来看一下“man diff”中的例子:

   -I RE  --ignore-matching-lines=RE
          Ignore changes whose lines all match RE.

好的,阅读完这篇文章后,我不知道它是什么意思。没有使用它的示例。"RE"是什么?它没有在任何地方说明。

接下来是这个宝石:

  --GTYPE-group-format=GFMT
          Similar, but format GTYPE input groups with GFMT.

   --line-format=LFMT
          Similar, but format all input lines with LFMT.

   --LTYPE-line-format=LFMT
          Similar, but format LTYPE input lines with LFMT.

   LTYPE is `old', `new', or `unchanged'.
          GTYPE is LTYPE or `changed'.

          GFMT may contain:

   %<     lines from FILE1

   %>     lines from FILE2

   %=     lines common to FILE1 and FILE2

   %[-][WIDTH][.[PREC]]{doxX}LETTER
          printf-style spec for LETTER

          LETTERs are as follows for new group, lower case for old group:

   F      first line number

   L      last line number

   N      number of lines = L-F+1

   E      F-1

   M      L+1

          LFMT may contain:

   %L     contents of line

   %l     contents of line, excluding any trailing newline

   %[-][WIDTH][.[PREC]]{doxX}n
          printf-style spec for input line number

          Either GFMT or LFMT may contain:

   %%     %

   %c'C'  the single character C

   %c'\OOO'
          the character with octal code OOO
我完全看不懂这段话。"input"是什么?它是两个文件还是只有"to"文件或"from"文件?"similar"指的是什么?句子中的"is"是什么意思,"GFMT 'is' LTYPE or `changed'"?它是指"可能被替换为"吗?如果是,那么为什么"GFMT"没有加引号、括号等呢?由于没有给出示例,所以无法知道;文档的措辞完全模糊不清。"GFMT may contain"是什么意思?"contain"是否意味着替换缩写GFMT的文本可以包含它?没有明确的示例,它就完全没用了。
如果你打算把手册写得这么神秘和含糊不清,对于那些不知道如何使用软件的人来说,为什么要费心写一个手册呢?在这一点上,它不是一个手册,而只是一个快速参考页面,供编写软件的人记住如何使用它。我想他们认为,如果你想知道它实际上是做什么的,你会直接阅读源代码。
我的时间很宝贵。我宁愿支付金钱来获得一个真正能够正确工作并具有适当文档的软件。
因为这些都失败了:
 diff -d --strip-trailing-cr --ignore-all-space --from-file=rest.phtml test.phtml

...无法忽略 \r 字符。

 diff -wd --strip-trailing-cr --ignore-all-space --from-file=rest.phtml test.phtml

...无法忽略 \r 字符。

 diff -wd --suppress-common-lines --strip-trailing-cr --ignore-all-space --from-file=rest.phtml test.phtml

...未能忽略 \r 字符。

 diff -wd test.phtml rest.phtml --suppress-common-lines --strip-trailing-cr --ignore-all-space

...未能忽略 \r 字符。

 diff -awd test.phtml rest.phtml --suppress-common-lines --strip-trailing-cr --ignore-all-space

...未能忽略 \r 字符。

如果它们是 \n 字符,当添加了 \n 字符时也会失败。

其中 test.phtml ==

foo

bar

和 rest.html ==

foobar

"diff" 命令总是会给你类似以下的结果:


*** 1,2 **** ! foo ! bar \ No newline at end of file

--- 1 ---- ! foobar \ No newline at end of file

...失败!


2
RE是一个正则表达式。 - Concrete Gannet
说得够激烈的,但没错,圣洁的手册页面很容易被解释(因此在某种程度上是无用的)。 - Peter Mortensen

2

dos2unix命令可帮助您首先将文件转换为一致的格式。 我相信它适用于几乎所有想象得到的平台,并且可以同时运行大量文件。 我相信Mac有一个可用的软件包。


通过convmode选项,dos2unix对Mac格式的文件提供了一些支持。考虑到这一点,可能可以创建一个一致(且独立)的转换,以便进行差异化/筛选。 - Rog
我之前写过一个mac2unix程序,结果那个程序最终成为了最佳解决方案... - Brian Postow
1
每天学点新东西!另外,有一个名为“flip”的命令可以适用于任何组合! - Brian Postow

0
我使用了以下的快速解决方法,但它有一些缺点(见下文): 1:进行差异比较并仅列出文件名。
diff -r -q dir1/ dir2/

2: 使用所用的编辑器打开并保存每个列出的文件,这将更改行尾。

3: 进行常规差异比较

缺点包括:

  • 不够稳健,容易出错
  • 如果有大量文件,则需要更多工作

最好使用dos2unix或flip等工具自动化第二步。 - Concrete Gannet

-1

这个不起作用。如果文件A包含“foo\rbar”,文件B包含“foobar”,它们会被认为是不同的。关键是要忽略所有空格,包括回车! - CommaToast
我认为那不对。如果你有两个文件,一个是foo<换行符>bar,另一个是foobar,你难道不会说它们是不同的吗? - Wisco crew
你说得对,在这种情况下,确实是不同的。我实际上是因为在寻找一种忽略换行符的方法而来到这个页面的,当它们的添加是文件中唯一的更改时,例如漂亮的 JSON 不会被视为与相同 JSON 的非漂亮形式不同。当然,对于像 YAML 这样没有“非漂亮”形式的东西,换行符是至关重要的。在评论之前我应该仔细阅读它...太多标签了... - CommaToast
链接已损坏(404)。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接