Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何使用shell脚本比较两个不同目录中具有相同名称的文件_Bash_Shell_Diff - Fatal编程技术网

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

Bash 如何使用shell脚本比较两个不同目录中具有相同名称的文件,bash,shell,diff,Bash,Shell,Diff,在继续使用SVN之前,我通常只需保存一个/develope/目录并在那里编辑和测试文件,然后将它们移动到/main/目录即可管理我的项目。当我决定转到SVN时,我需要确保目录确实是同步的 那么,编写shell脚本[bash]递归比较两个不同目录中同名文件的好方法是什么呢 注意:上面使用的目录名仅用于示例。我不建议将代码存储在顶层:)。diff命令有一个-r选项,用于递归比较目录: diff -r /develop /main [我在某个地方读到,回答你自己的问题是可以的,所以这里是:)] 我试

在继续使用SVN之前,我通常只需保存一个
/develope/
目录并在那里编辑和测试文件,然后将它们移动到
/main/
目录即可管理我的项目。当我决定转到SVN时,我需要确保目录确实是同步的

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


注意:上面使用的目录名仅用于示例。我不建议将代码存储在顶层:)。

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

diff -r /develop /main

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

我试过这个,效果很好

[/]$ 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

还有其他想法吗?

我现有的差异允许递归差异:

diff -r main develop
但是使用shell脚本:

( cd main ; find . -type f -exec diff {} ../develop/{} ';' )
它只会以这种方式为您提供更改摘要:)

如果只想查看新的/丢失的文件

如果你想把它们裸露出来:

diff -rqu /develop /main | sed -rn "/^Only/s/^Only in (.+?): /\1/p"
经典的(System V Unix)答案是
dircmp dir1 dir2
,这是一个shell脚本,在开始时列出在dir1但不是dir2或dir2但不是dir1中找到的文件(输出的第一页,来自
pr
命令,用标题分页),然后通过分析比较每个常用文件(相同、不同、目录是最常见的结果)

这似乎正在消失-如果您需要,我有一个独立的重新实现。它不是火箭科学(
cmp
是您的朋友)。

下面是我的一个(有些混乱)脚本示例,它将:

  • 在两个递归过程中,根据文件和目录出现在哪个目录(或两者都出现)对数组中的文件和目录进行排序
  • 出现在两个目录中的文件将在两个数组中再次排序,这取决于if
    diff-q
    确定它们是否不同
  • 对于
    diff
    声明相等的文件,显示并比较时间戳
希望它能被发现有用-干杯

EDIT2:(实际上,它可以很好地处理远程文件-问题是在本地文件和远程文件之间的diff操作期间未处理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
  • --试运行
    -仅模拟,不更新/传输文件
  • -r
    -递归到目录中
  • -v
    -verbose(但与文件更改信息无关)
  • --cvs排除
    -忽略
    .svn
    文件
  • -i
    -“--逐项列出更改:输出所有更新的更改摘要”
下面是
manrsync
的一个简短摘录,它解释了
-i
所显示的信息(例如,上面的
>f.st.
字符串):

“%i”转义有一个11个字母长的神秘输出。
一般格式类似于字符串YXcstpoguax,其中Y是
替换为正在执行的更新类型,X替换为
文件类型,以及其他字母表示可能
如果正在修改,则输出。
替换Y的更新类型如下所示:
o A<表示文件正在传输到远程服务器
主机(已发送)。
o A>表示文件正在传输到本地服务器
主持人(已收到)。
o A c表示正在对进行本地更改/创建
项目(例如创建目录或
更改符号链接等)。
...
替换X的文件类型为:f表示文件,d表示文件
目录,L表示符号链接,D表示设备,S表示
特殊文件(例如命名套接字和FIFO)。
上面字符串中的其他字母是实际的字母
如果项目的关联属性为
正在更新或为“.”表示无更改。有三个例外
是:(1)新创建的项目将每个字母替换为“+”,
(2) 一个相同的项目将点替换为空格,(3)一个
....


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

从技术上讲不是bash,但如果您的diff支持它,它是一个更好的解决方案。对我来说很有用!谢谢。另外,对于更漂亮的打印,diff-ru/develope/main也可以在macOS上工作,它只是工作而已™ 没有
-r
标志。这可以工作,但它会截断最后一个目录“斜杠”,例如:abc/def/ghi结果显示为abc/defghi
diff -rqu /develop /main | sed -rn "/^Only/s/^Only in (.+?): /\1/p"
$ # 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
...
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
....