diff
在类似Unix的操作系统上,diff命令分析两个文件并打印不同的行。本质上,它输出一组指令,说明如何更改一个文件以使其与第二个文件相同。
查看英文版
1 diff 运行系统环境
2 diff 描述
3 diff 语法
4 diff 例子
diff 运行系统环境
Unix&Linux
diff 描述
该DIFF软件实际上并没有改变它比较文件。但是,它可以选择为程序ed或ex生成脚本(如果指定了-e选项),该脚本可用于应用更改。
例如,考虑两个文件,file1.txt和file2.txt。
如果file1.txt包含以下四行文本:
I need to buy apples. I need to run the laundry. I need to wash the dog. I need to get the car detailed.
...和file2.txt包含以下四行:
I need to buy apples. I need to do the laundry. I need to wash the car. I need to get the dog detailed.
...然后我们可以使用diff通过以下命令自动为我们显示两个文件中哪些行不同:
diff file1.txt file2.txt
...的输出将是:
2,4c2,4 < I need to run the laundry. < I need to wash the dog. < I need to get the car detailed. --- > I need to do the laundry. > I need to wash the car. > I need to get the dog detailed.
让我们看一下此输出的含义。要记住的重要一点是,当diff向您描述这些差异时,它是在说明性上下文中进行的:它告诉您如何更改第一个文件以使其与第二个文件匹配。
diff输出的第一行将包含:
- 第一个文件对应的行号,
- 一个字母(a表示添加,c表示更改,d表示删除),以及
- 与第二个文件相对应的行号。
在我们的以上“输出2,4c2,4 ”是指:“行2通过4中的第一个文件需要被Ç上吊匹配线2通过4在第二个文件”。然后告诉我们每个文件中的那些行:
- 以<开头的行是第一个文件中的行;
- 以>开头的行是第二个文件中的行。
三个破折号(“ --- ”)仅将文件1和文件2的行分开。
让我们看另一个例子。假设我们的两个文件如下所示:
file1.txt:
I need to go to the store. I need to buy some apples. When I get home, I'll wash the dog.
file2.txt:
I need to go to the store. I need to buy some apples. Oh yeah, I also need to buy grated cheese. When I get home, I'll wash the dog.
diff file1.txt file2.txt
输出:
2a3 > Oh yeah, I also need to buy grated cheese.
这里,输出是在告诉我们“行后2中的第一个文件,一个行必须是一个dded:线3从第二个文件。” 然后,它告诉我们那条线是什么。
现在,让我们看看diff告诉我们需要删除一行时的外观。
文件1:
I need to go to the store. I need to buy some apples. When I get home, I'll wash the dog. I promise.
file2:
I need to go to the store. I need to buy some apples. When I get home, I'll wash the dog.
我们的命令:
diff file1.txt file2.txt
输出:
4d3 < I promise.
这里,输出是告诉我们“你需要d elete线4中的第一个文件,使这两个文件保持同步的行3 ”。然后,它向我们显示了需要删除的行的内容。
在上下文中查看差异输出
上面的示例显示了diff的默认输出。它旨在由计算机而不是人类读取,因此出于人类目的,有时它有助于查看更改的上下文。
GNU diff是大多数Linux用户将使用的版本,它提供了两种不同的方式来执行此操作:“上下文模式”和“统一模式”。
要查看上下文模式下的差异,请使用-c选项。例如,假设file1.txt和file2.txt包含以下内容:
file1.txt:
apples oranges kiwis carrots
file2.txt:
apples kiwis carrots grapefruits
让我们看一下这两个文件的差异的上下文输出。我们的命令是:
diff -c file1.txt file2.txt
我们的输出如下所示:
*** file1.txt 2014-08-21 17:58:29.764656635 -0400 --- file2.txt 2014-08-21 17:58:50.768989841 -0400 *************** *** 1,4 **** apples - oranges kiwis carrots --- 1,4 ---- apples kiwis carrots + grapefruits
此输出的前两行向我们显示有关“从”文件(文件1)和“至”文件(文件2)的信息。它列出了每个文件的文件名,修改日期和修改时间,每行一个。“ from”文件用“ *** ”表示,“ to”文件用“ --- ”表示。
行“ *************** ”只是一个分隔符。
下一行具有三个星号(“ *** ”),其后是从第一个文件开始的行范围(在本例中为第1至4行,用逗号分隔)。然后是四个星号(“ **** ”)。
然后它向我们显示了这些行的内容。如果该行未更改,则以两个空格作为前缀。但是,如果更改了该行,则会在其前面加上指示性字符和空格。字符含义如下:
字符character | 含义 |
! | 表示此行是一个或多个需要更改的行的一部分。在另一个文件的上下文中,也有一组对应的行以“ ! ”为前缀。 |
+ | 指示第二个文件中需要添加到第一个文件中的一行。 |
-- | 指示第一个文件中需要删除的一行。 |
从第一个文件开始的行之后,有三个破折号(“ --- ”),然后是行范围,然后是四个破折号(“ ---- ”)。这表示第二个文件中的行范围将与第一个文件中的更改同步。
如果需要更改的部分不止一个,diff将逐个显示这些部分。第一个文件中的行仍将以“ *** ”表示,第二个文件中的行仍将以“ --- ”表示。
统一模式
统一模式(-u选项)类似于上下文模式,但是不显示任何冗余信息。这是一个示例,使用与我们上一个示例相同的输入文件:
file1.txt:
apples oranges kiwis carrots
file2.txt:
apples kiwis carrots grapefruits
我们的命令:
diff -u file1.txt file2.txt
输出:
--- file1.txt 2014-08-21 17:58:29.764656635 -0400 +++ file2.txt 2014-08-21 17:58:50.768989841 -0400 @@ -1,4 +1,4 @@ apples -oranges kiwis carrots +grapefruits
输出与上面类似,但是您可以看到,差异被“统一”为一组。
发现目录内容中的差异
diff还可以通过提供目录名而不是文件名来比较目录。请参阅示例部分。
使用diff创建编辑脚本
所述-e选项告诉差异以输出一个脚本,其可以由编辑程序使用编或EX,包含命令的序列。这些命令是c(更改),a(添加)和d(删除)的组合,当由编辑器执行时,它们将修改file1的内容(在diff命令行上指定的第一个文件),使其匹配file2的内容(指定的第二个文件)。
假设我们有两个文件,其内容如下:
file1.txt:
Once upon a time, there was a girl named Persephone. She had black hair. She loved her mother more than anything. She liked to sit outside in the sunshine with her cat, Daisy. She dreamed of being a painter when she grew up.
file2.txt
Once upon a time, there was a girl named Persephone. She had red hair. She loved chocolate chip cookies more than anything. She liked to sit outside in the sunshine with her cat, Daisy. She would look up into the clouds and dream of being a world-famous baker.
我们可以运行以下命令来使用diff分析这两个文件,并生成一个脚本来根据file1.txt的内容创建一个与file2.txt相同的文件:
diff -e file1.txt file2.txt
...输出将如下所示:
5c She would look up into the clouds and dream of being a world-famous baker. . 2,3c She had red hair. She loved chocolate chip cookies more than anything. .
请注意,更改以相反的顺序列出:更靠近文件末尾的更改将首先列出,而靠近文件开头的更改将最后列出。此顺序是为了保留行号。如果我们首先在文件的开头进行了更改,则可能稍后在文件中更改行号。因此,脚本从末尾开始,然后向后工作。
“:在这里,该脚本是告诉编辑程序Ç焊割线5至(下面的行),并且变更线2通过3至(以下两行)”。
接下来,我们应该将脚本保存到文件中。我们可以使用>运算符将diff输出重定向到文件,如下所示:
diff -e file1.txt file2.txt> my-ed-script.txt
该命令不会在屏幕上显示任何内容(除非有错误);而是将输出重定向到文件my-ed-script.txt。如果my-ed-script.txt不存在,它将被创建;如果已经存在,它将被覆盖。
如果我们现在使用cat命令检查my-ed-script.txt的内容...
cat my-ed-script.txt
...我们将看到与上面显示的脚本相同的脚本。
但是,仍然缺少一件事:我们需要脚本来告诉ed实际写入文件。脚本中缺少的只是w命令,它将写入更改。我们可以通过回显字母“ w ”并使用>>运算符将其添加到我们的文件中,将其添加到脚本中。(>>运算符与>运算符相似。它将输出重定向到文件,但不覆盖目标文件,而是追加到文件的末尾。)命令如下所示:
echo“ w” >> my-ed-script.txt
现在,我们可以再次运行cat命令来检查脚本是否已更改:
cat my-ed-script.txt
5c She would look up into the clouds and dream of being a world-famous baker. . 2,3c She had red hair. She loved chocolate chip cookies more than anything. . w
现在,当我们的脚本发布给ed时,将进行更改并将更改写入磁盘。
那么我们怎么ed做到这一点?
我们可以使用以下命令将此脚本发布给ed,告诉它覆盖我们的原始文件。破折号(“ - ”)指示ed从标准输入中读取,而<运算符将脚本定向到该输入。本质上,系统输入脚本中的任何内容作为编辑程序的输入。该命令如下所示:
ed-file1.txt
该命令不显示任何内容,但是如果我们查看原始文件的内容...
cat file1.txt
Once upon a time, there was a girl named Persephone. She had red hair. She loved chocolate chip cookies more than anything. She liked to sit outside in the sunshine with her cat, Daisy. She would look up into the clouds and dream of being a world-famous baker.
...我们可以看到file1.txt现在与file2.txt完全匹配。
警告!在此示例中,ed改写了原始文件file1.txt的内容。运行脚本后,file1.txt的原始文本消失了,因此在运行这些命令之前,请确保您了解自己在做什么!
常用差异选项
以下是一些有用的差异选项,请注意:
-b | 忽略仅更改空白量(例如空格或制表符)的任何更改。 |
-w | 完全忽略空格。 |
-B | 计算差异时,请忽略空白行。 |
-y | 在两列中显示输出。 |
这些只是一些最常用的diff选项。以下是diff选项及其功能的完整列表。
查看英文版
diff 语法
diff [OPTION]... FILES
选件
--normal | 输出“normal”差异,这是默认值。 | ||||||
-q,--brief | 仅当文件不同时才产生输出。如果没有差异,则什么也不输出。 | ||||||
-s,-- report-identical-files | 当两个文件相同时报告。 | ||||||
-c,-C NUM,-- context [ = NUM ] | 提供NUM(默认3)行上下文。 | ||||||
-u,-U NUM,-- unified [ = NUM ] | 提供NUM(默认3)行统一上下文。 | ||||||
-e,-- ed | 输出一个ed脚本。 | ||||||
-n,-- rcs | 输出RCS格式的差异。 | ||||||
-y,--side by | 将输出格式化为两列。 | ||||||
-W,--width = NUM | 输出最多NUM(默认为130)个打印列。 | ||||||
--left-column | 仅输出公共行的左列。 | ||||||
--suppress-common-lines | 不要输出两个文件之间共有的行。 | ||||||
-p,-- show-c-function | 对于包含C代码的文件,还要显示每个C函数更改。 | ||||||
-F,-- show-function-line = RE | 显示与正则表达式RE匹配的最新行。 | ||||||
--label LABEL | 显示输出时,请使用标签LABEL代替文件名。对于多个标签,可以多次发出此选项。 | ||||||
-t,-- expand-tabs | 将选项卡扩展到输出中的空格。 | ||||||
-T,-- initial-tab | 如有必要,可通过在标签前添加标签来使标签对齐。 | ||||||
--tabsize = NUM | 将制表位定义为NUM(默认为8)列。 | ||||||
--suppress-blank-empty | 在空输出行之前禁止空格或制表符。 | ||||||
-l,--paginate | 将输出通过pr传递给分页。 | ||||||
-r,--recursive | 递归比较找到的所有子目录。 | ||||||
-N,--new-file | 如果指定的文件不存在,请像执行空白文件一样执行diff。 | ||||||
--unidirectional-new-file | 与-n相同,但仅适用于第一个文件。 | ||||||
--ignore-file-name-case | 比较文件名时忽略大小写。 | ||||||
--no-ignore-file-name-case | 比较文件名时要考虑大小写。 | ||||||
-x,-- exclude = PAT | 排除与文件名模式PAT匹配的文件。 | ||||||
-X,-- exclude-from = FILE | 排除与文件FILE中的任何文件名模式匹配的文件。 | ||||||
-S,-- starting-file = FILE | 比较目录时从文件FILE开始。 | ||||||
--from-file = FILE1 | 比较FILE1和所有操作数; FILE1可以是目录。 | ||||||
--to-file = FILE2 | 将所有操作数与FILE2比较;FILE2可以是目录。 | ||||||
-i,-- ignore-case | 忽略文件内容中的大小写差异。 | ||||||
-E,-- ignore-tab-expansion | 忽略由于选项卡扩展而引起的更改。 | ||||||
-b,-- ignore-space-change | 忽略空白量的变化。 | ||||||
-w,-- ignore-all-space | 忽略所有空白。 | ||||||
-B,-- ignore-blank-lines | 忽略所有行均为空白的更改。 | ||||||
-I,-- ignore-matching-lines = RE | 忽略所有行都与正则表达式 RE匹配的更改。 | ||||||
-a,-- text | 将所有文件视为文本。 | ||||||
--strip-trailing-cr | 带钢拖尾回车输入。 | ||||||
-D,-- ifdef = NAME | 输出带有“ #ifdef NAME ”差异的合并文件。 | ||||||
- GTYPE -group-format= GFMT | 使用GFMT格式化GTYPE输入组。 | ||||||
--line-format = LFMT | 用LFMT格式化所有输入行。 | ||||||
- LTYPE -line-fo= LFMT |
格式化LTYPE与输入线LFMT。 这些格式选项可对diff的输出进行细粒度的控制,从而使-D / --ifdef通用化。 LTYPE是旧的,新的或不变的。 GTYPE可以是任何LTYPE值,也可以是更改的值。 GFMT(但不是LFMT)可能包含:
|
||||||
% [ - ] [ WIDTH ] [ 。[ PREC ]] { doxX } LETTER | 的printf风格的规格为LETTER |
对于新组,LETTER如下,对旧组,小写:
F | 第一行号。 |
大号 | 最后一行 |
ñ | 行数= L - F + 1。 |
E | F - 1 |
M | L + 1 |
%(A = B ?T :E) | 如果一个等于乙再牛逼其他E. |
LFMT(仅)可能包含:
%L | 行的内容。 |
%l | 行的内容,不包括任何尾随的换行符。 |
% [ - ] [ WIDTH ] [ 。[ PREC ]] { doxX } n | 输入行号的printf样式规范。 |
无论GFMT和LFMT可能包含:
%% | 文字%。 |
%C ' C ' | 单个字符C。 |
%c'\ OOO' | 八进制代码OOO的字符。 |
C | 字符C(其他字符代表自己)。 |
-d,--minimal | 尝试找到较小的一组更改。 |
--horizon-lines = NUM | 保留NUM行共同的前缀和后缀。 |
--speed-large-files | 假定大文件和许多分散的小更改。 |
--help | 显示帮助消息并退出。 |
-v,-- version | 输出版本信息并退出。 |
文件采用“ FILE1 FILE2 ”或“ DIR1 DIR2 ”或“ DIR FILE ...”或“ FILE ... DIR ”的形式。
如果给出了--from -file或--to-file选项,则对FILE没有任何限制。如果FILE是破折号(“ - ”),则diff从标准输入读取。
如果输入相同,则退出状态为0;如果输入不同,则退出状态为1;如果diff遇到任何麻烦,则退出状态为2。
查看英文版
diff 例子
这是一个示例,使用diff通过-y选项并排检查两个文件之间的差异,给定以下输入文件:
file1.txt:
apples oranges kiwis carrots
file2.txt:
apples kiwis carrots grapefruits
diff -y file1.txt file2.txt
输出:
apples apples oranges < kiwis kiwis carrots carrots > grapefruits
如所承诺的,这是一个使用diff比较两个目录的示例:
diff dir1 dir2
输出:
Only in dir1: tab2.gif Only in dir1: tab3.gif Only in dir1: tab4.gif Only in dir1: tape.htm Only in dir1: tbernoul.htm Only in dir1: tconner.htm Only in dir1: tempbus.psd
查看英文版
未知的网友