您可以通过控制 GNU diff 输出中旧/新/未更改行的格式来实现这一点:
diff --new-line-format="" --unchanged-line-format="" file1 file2
输入文件应该被排序,这样才能正常工作。使用bash(和zsh),您可以使用进程替换<( )就地排序:
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
在上面的 new 和 unchanged 行被抑制,所以只有 changed (即在您的情况下删除的行)被输出。您还可以使用一些其他解决方案不提供的diff 选项,例如-i 来忽略大小写,或者使用各种空格选项(-E、-b、-v 等)来实现不太严格的匹配。
说明
--new-line-format、--old-line-format 和--unchanged-line-format 选项让您控制diff 格式化差异的方式,类似于printf 格式说明符。这些选项分别格式化 new(添加)、old(删除)和 unchanged 行。将一个设置为空 "" 会阻止输出那种行。
如果您熟悉 unified diff 格式,您可以部分地重新创建它:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
%L 说明符是有问题的行,我们用“+”“-”或“”作为前缀,例如 diff -u
(请注意,它只输出差异,它缺少每个分组更改顶部的 --- +++ 和 @@ 行)。
您还可以使用它来做其他有用的事情,例如 number each line 和 %dn。
diff 方法(连同其他建议 comm 和 join)仅产生带有 sorted 输入的预期输出,但您可以使用 <(sort ...) 就地排序。这是一个简单的awk (nawk) 脚本(受 Konsolebox 答案中链接到的脚本的启发),它接受任意排序的输入文件, 并且 按照它们在 file1 中出现的顺序输出缺失的行。
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
这会将file1的全部内容逐行存储在行号索引数组ll1[]中,并将file2的全部内容逐行存储在行内容索引关联数组ss2[]中。读取两个文件后,遍历ll1 并使用in 运算符确定file1 中的行是否存在于file2 中。 (如果有重复,这将对diff 方法有不同的输出。)
如果文件足够大以至于存储它们都会导致内存问题,您可以通过仅存储 file1 并在读取 file2 的过程中删除匹配项来以 CPU 换取内存。
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
上面将file1的全部内容存储在两个数组中,一个以行号ll1[]为索引,一个以行内容ss1[]为索引。然后在读取 file2 时,从ll1[] 和ss1[] 中删除每个匹配的行。最后输出 file1 中的剩余行,保持原始顺序。
在这种情况下,对于上述问题,您还可以分而治之,使用 GNU split(过滤是 GNU 扩展),重复运行文件 1 块并每次完全读取文件 2时间:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
注意- 的使用和位置,意思是stdin 在gawk 命令行上。这是由来自 file1 的 split 以每次调用 20000 行的块提供的。
对于非 GNU 系统上的用户,几乎可以肯定,您可以获得一个 GNU coreutils 软件包,包括在 OSX 上作为 Apple Xcode 工具的一部分,它提供 GNU diff、awk,尽管只有一个 POSIX/ BSD split 而不是 GNU 版本。