文件比对工具diff、cmp、patch


文件比对工具diff、cmp、patch

回到顶部

什么时候会用到文件的比对啊?通常是同一个软件包的不同版本之间,比较配置文件与原始档的差 异。 很多时候所谓的文件比对,通常是用在 ASCII 纯文本档的比对上的!那么比对文件的命令 有哪些?最常见的就是 diff 啰! 另外,除了 diff 比对之外,我们还可以藉由 cmp 来比对非纯文 本档!同时,也能够藉由 diff 建立的分析檔, 以处理补丁 (patch) 功能的文件呢!就来玩玩先!
diff
diff 就是用在比对两个文件之间的差异的,并且是以行为单位来比对的!一般是用在 ASCII 纯文本 档的比对上。 由于是以行为比对的单位,因此 diff 通常是用在同一的文件(或软件)的新旧版本差异 上! 举例来说,假如我们要将 /etc/passwd 处理成为一个新的版本,处理方式为: 将第四行删除, 第六行则取代成为no six line,新的文件放置到 /tmp/test 里面,那么应该怎么做?

              [peter@study ~]$ mkdir -p /tmp/testpw #先建立测试用的目录
              [peter@study ~]$ cd /tmp/testpw
              [peter@study testpw]$ cp /etc/passwd passwd.old
              [peter@study testpw]$ cat /etc/passwd | sed -e '4d' -e '6c no six line' > passwd.new
            
# 注意一下, sed 后面如果要接超过两个以上的动作时,每个动作前面得加 -e 才行!
# 通过这个动作,在 /tmp/testpw 里面便有新旧的 passwd 文件存在了!
接下来讨论一下关于 diff 的用法吧!
              [peter@study ~]$ diff [-bBi] from-file to-file
            
选项与参数:
from-file :一个文件名,作为原始比对文件的文件名; to-file :一个文件名,作为目的比对文件的文件名; 注意,from-file 或 to-file 可以 - 取代,那个 - 代表Standard input之意。 -b :忽略一行当中,仅有多个空白的差异(例如 "about me" 与 "about -B :忽略空白行的差异。 -i :忽略大小写的不同。 me" 视为相同
范例一:比对 passwd.old 与 passwd.new 的差异:
              [peter@study testpw]$ diff passwd.old passwd.new
              4d3
            
#左边第四行被删除 (d) 掉了,基准是右边的第三行
< adm:x:3:4:adm:/var/adm:/sbin/nologin 6c5
#这边列出左边(<)文件被删除的那一行内容
#左边文件的第六行被取代 (c) 成右边文件的第五行
< sync:x:5:0:sync:/sbin:/bin/sync
#左边(<)文件第六行内容
--- > no six line
#右边(>)文件第五行内容
# 很聪明吧!用 diff 就把我们刚刚的处理给比对完毕了!
用 diff 比对文件真的是很简单喔!不过,你不要用 diff 去比对两个完全不相干的文件,因为比不出 个啥咚咚! 另外, diff 也可以比对整个目录下的差异喔!举例来说,我们想要了解一下不同的开机 执行等级 (runlevel) 内容有啥不同?假设你已经知道执行等级 0 与 5 的启动脚本分别放置到 /etc/rc0.d 及 /etc/rc5.d , 则我们可以将两个目录比对一下:
              [peter@study ~]$ diff /etc/rc0.d/ /etc/rc5.d/
              Only in /etc/rc0.d/: K90network
              Only in /etc/rc5.d/: S10network
            
我们的 diff 很聪明吧!还可以比对不同目录下的相同文件名的内容,这样真的很方便喔~
cmp
相对于 diff 的广泛用途, cmp 似乎就用的没有这么多了~ cmp 主要也是在比对两个文件,他主要 利用字节单位去比对, 因此,当然也可以比对 binary file 啰~(还是要再提醒喔, diff 主要是 以行为单位比对, cmp 则是以字节为单位去比对,这并不相同!)
              [peter@study ~]$ cmp [-l] file1 file2
            
选项与参数:
-l :将所有的不同点的字节处都列出来。因为 cmp 预设仅会输出第一个发现的不同点。
范例一:用 cmp 比较一下 passwd.old 及 passwd.new
              [peter@study testpw]$ cmp passwd.old passwd.new
              passwd.old passwd.new differ: char 106, line 4
            
看到了吗?第一个发现的不同点在第四行,而且字节数是在第 106 个字节处!这个 cmp 也可以用 来比对 binary 啦! ^_^
patch
patch 这个命令与 diff 可是有密不可分的关系啊!我们前面提到, diff 可以用来分辨两个版本之间的 差异, 举例来说,刚刚我们所建立的 passwd.old 及 passwd.new 之间就是两个不同版本的文件。 那 么,如果要升级呢?就是将旧的文件升级成为新的文件时,应该要怎么做呢? 其实也不难 啦!就是先比较先旧版本的差异,并将差异档制作成为补丁档,再由补丁档更新旧文件即可。 举 例来说,我们可以这样做测试:
范例一:以 /tmp/testpw 内的 passwd.old 与 passwd.new
制作补丁文件
              [peter@study testpw]$ diff -Naur passwd.old passwd.new > passwd.patch
              [peter@study testpw]$ cat passwd.patch
              --- passwd.old 2015-07-14 22:37:43.322535054 +0800
              +++ passwd.new 2015-07-14 22:38:03.010535054 +0800
              @@ -1,9 +1,8 @@


              #新旧文件的信息
              #新旧文件要修改数据的界定范围,旧档在 1-9 行,新檔在 1-8 行


              root:x:0:0:root:/root:/bin/bash
              bin:x:1:1:bin:/bin:/sbin/nologin
              daemon:x:2:2:daemon:/sbin:/sbin/nologin
              -adm:x:3:4:adm:/var/adm:/sbin/nologin
              #左侧文件删除
              lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
              -sync:x:5:0:sync:/sbin:/bin/sync #左侧文件删除
              +no six line #右侧新档加入
              shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
              halt:x:7:0:halt:/sbin:/sbin/halt
              mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
            
一般来说,使用 diff 制作出来的比较文件通常使用扩展名为 .patch 啰。至于内容就如同上面介绍的 样子。 基本上就是以行为单位,看看哪边有一样与不一样的,找到一样的地方,然后将不一样的地 方取代掉! 以上面表格为例,新文件看到 - 会删除,看到 + 会加入!好了,那么如何将旧的文件 更新成为新的内容呢? 就是将 passwd.old 改成与 passwd.new 相同!可以这样做:
# 因为 CentOS 7 预设没有安装 patch 这个软件,因此得要依据之前介绍的方式来安装一下软件!
# 请记得拿出原本光盘并放入光驱当中,这时才能够使用底下的方式来安装软件!
              [peter@study ~]$ su -
              [root@initroot ~]# mount /dev/sr0 /mnt
              [root@initroot ~]# rpm -ivh /mnt/Packages/patch-2.*
              [root@initroot ~]# umount /mnt
              [root@initroot ~]# exit
            
# 通过上述的方式可以安装好所需要的软件,且无须上网。接下来让我们开始操作 patch 啰!
              [peter@study ~]$ patch -pN < patch_file
            
#更新
              [peter@study ~]$ patch -R -pN < patch_file #还原
            
选项与参数:
-p :后面可以接取消几层目录的意思。
-R :代表还原,将新的文件还原成原来旧的版本。
范例二:将刚刚制作出来的 patch file 用来更新旧版数据
              [peter@study testpw]$ patch -p0 < passwd.patch
              patching file passwd.old
              [peter@study testpw]$ ll passwd*
              -rw-rw-r--. 1 peter peter 2035 Jul 14 22:38 passwd.new
              -rw-r--r--. 1 peter peter 2035 Jul 14 23:30 passwd.old
            
#文件一模一样!
范例三:恢复旧文件的内容
              [peter@study testpw]$ patch -R -p0 < passwd.patch
              [peter@study testpw]$ ll passwd*
              -rw-rw-r--. 1 peter peter 2035 Jul 14 22:38 passwd.new
              -rw-r--r--. 1 peter peter 2092 Jul 14 23:31 passwd.old
            
# 文件就这样恢复成为旧版本啰
为什么这里会使用 -p0 呢?因为我们在比对新旧版的数据时是在同一个目录下, 因此不需要减去目 录啦!如果是使用整体目录比对 (diff 旧目录 新目录) 时, 就得要依据建立 patch 文件所在目录来 进行目录的删减啰!
更详细的 patch 用法我们会在后续的第五篇的原始码编译 (第二十一章)再跟大家介绍, 这里仅是介 绍给你,我们可以利用 diff 来比对两个文件之间的差异, 更可进一步利用这个功能来制作修补文件 (patch file) ,让大家更容易进行比对与升级呢!很不赖吧! ^_^

相关阅读:
本文由initroot编辑整理,转载请注明www.initroot.com

100次点赞 100次阅读