如何使用shell脚本比较两个不同目录中具有相同名称的文件

时间:2008-09-23 08:15:58

标签: bash shell diff

在继续使用SVN之前,我曾经通过简单地保留/develop/目录并在那里编辑和测试文件来管理我的项目,然后将它们移动到/main/目录。当我决定转移到SVN时,我需要确保目录确实是同步的。

那么,编写shell脚本[bash]以递归比较两个不同目录中具有相同名称的文件有什么好方法呢?

注意:上面使用的目录名称仅供样本使用。我不建议将代码存储在顶层:)。

6 个答案:

答案 0 :(得分:30)

diff命令有一个-r选项来递归比较目录:

diff -r /develop /main

答案 1 :(得分:8)

diff -rqu /develop /main

它只会给你一个改变的总结:)

如果您只想查看新/缺少的文件

diff -rqu /develop /main | grep "^Only

如果你想让他们裸露:

diff -rqu /develop /main | sed -rn "/^Only/s/^Only in (.+?): /\1/p"

答案 2 :(得分:4)

我可用的差异允许递归差异:

diff -r main develop

但是使用shell脚本:

( cd main ; find . -type f -exec diff {} ../develop/{} ';' )

答案 3 :(得分:1)

[我在某个地方读到了回答你自己的问题是好的,所以这里有:)]

我试过这个,而且效果很好

[/]$ cd /develop/
[/develop/]$ find | while read line; do diff -ruN "/main/$line" $line; done |less

您可以选择仅比较特定文件[例如,仅编译.php文件],将上述行编辑为

[/]$ cd /develop/
[/develop/]$ find -name "*.php" | while read line; do diff -ruN "/main/$line" $line; done |less

还有其他想法吗?

答案 4 :(得分:1)

这是我的一个(有点凌乱)脚本的例子dircompare.sh,它将:

  • 在数组中对文件和目录进行排序,具体取决于它们在两个递归传递中发生的目录(或两者)
  • 两个目录中出现的文件再次按两个数组排序,具体取决于diff -q是否确定它们是否不同
  • 表示diff声称相同的文件,显示和比较时间戳

希望它有用 - 干杯!

EDIT2:(实际上,它适用于远程文件 - 在本地和远程文件之间的差异操作期间问题是未处理的Ctrl-C信号,这可能需要一段时间;脚本现在更新了陷阱来处理 - 但是,将下一个编辑留在下面以供参考):

编辑:...除了它似乎使我的服务器崩溃了一个远程ssh目录(我尝试使用~/.gvfs)...所以这不再是bash,而是另一种我猜测是使用rsync,这是一个例子:

$ # get example revision 4527 as testdir1
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@4527 testdir1

$ # get earlier example revision 2729 as testdir2
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@2729 testdir2

$ # use rsync to generate a list 
$ rsync -ivr --times --cvs-exclude --dry-run testdir1/ testdir2/
sending incremental file list
.d..t...... ./
>f.st...... CMakeLists.txt
>f.st...... MACCS.txt
>f..t...... SMARTS_InteLigand.txt
...
>f.st...... atomtyp.txt
>f+++++++++ babel_povray3.inc
>f.st...... bin2hex.pl
>f.st...... bondtyp.h
>f..t...... bondtyp.txt
...

请注意:

  • 要实现上述目标,您不能忘记/
  • 目录名称末尾的尾部斜杠rsync
  • --dry-run - 仅模拟,不更新/传输文件
  • -r - 递归目录
  • -v - 详细(但与文件更改信息相关)
  • --cvs-exclude - 忽略.svn个文件
  • -i - “--itemize-changes:输出所有更新的更改摘要”

以下是man rsync的简短摘录,其中解释了-i显示的信息(例如,上面的>f.st......字符串):

The  "%i"  escape  has a cryptic output that is 11 letters long.
The general format is like the string YXcstpoguax,  where  Y  is
replaced  by the type of update being done, X is replaced by the
file-type, and the other letters represent attributes  that  may
be output if they are being modified.

The update types that replace the Y are as follows:

o      A  < means that a file is being transferred to the remote
       host (sent).

o      A > means that a file is being transferred to  the  local
       host (received).

o      A  c  means that a local change/creation is occurring for
       the item (such as the creation  of  a  directory  or  the
       changing of a symlink, etc.).

...
The file-types that replace the X are: f for a file, a d  for  a
directory,  an  L for a symlink, a D for a device, and a S for a
special file (e.g. named sockets and fifos).

The other letters in the string above  are  the  actual  letters
that  will be output if the associated attribute for the item is
being updated or a "." for no change.  Three exceptions to  this
are:  (1)  a newly created item replaces each letter with a "+",
(2) an identical item replaces the dots with spaces, and (3)  an
....

确实有点神秘 - 但至少它显示了ssh的基本目录比较。干杯!

答案 5 :(得分:0)

经典(System V Unix)答案是dircmp dir1 dir2,这是一个shell脚本,它会列出在dir1但不是dir2或dir2中找到的文件但在开头没有dir1(输出的第一页,从pr命令,用标题分页),然后将每个公共文件与分析进行比较(相同,不同,目录是最常见的结果)。

这似乎是在消失的过程中 - 如果你需要,我可以独立重新实现它。这不是火箭科学(cmp是你的朋友)。