3

我想要一个可以在任意 bash 流上使用的差异包装器,它只打印差异直到最短的行长。这对于常规文件很容易,只需阅读两次即可:

~/bin/mindiff:
min=$(calc -p 'min(' $(wc -l < "$1") ', ' $(wc -l < "$2") ')')
diff <(head -$min "$1")  <(head -$min "$2")

(我发现这对于检查运行时文本处理输出的差异非常有用。)

注意:我不希望逐行进行差异。我想要上面的脚本做什么(它允许跨越多行的差异),但是在流上工作。我只是不希望由于一个流/文件比另一个长而导致底部混乱。我更喜欢调用常规差异,以便我可以传递任何常规差异选项,如 -B1、-y --suppress-common-lines -W180、-U1 管道到 dwdiff 以获取带有颜色的花哨的单词差异等。

但是,我希望能够在任意流上调用它,只读取一次,例如

mindiff <(sed 's/fluff//' /tmp/out) <(ssh server sed 's/fluff//' /tmp/out)

在一些#bash 向导的帮助下,我得到了这个 awk 助手,它并行读取两个流直到一个结束,然后运行 ​​diff:

mkfifo a b

awk '
BEGIN{ f2=ARGV[2];ARGC-- }
( (getline line <f2)>0 ) { print > "a"; print line > "b" }
' "$1" "$2" &

diff a b

完整的脚本

它适用于短玩具示例,但如果我尝试类似

mindiff <(yes |head -40000) <(yes |head -40000)

它只是挂起。添加“打印NR;” 到 awk 显示它上升到第 36865 行(而<(yes yesyes)它上升到 10533,所以它似乎允许一定数量的字节,而不管行数如何)。

添加system("")到 flush awk 每一行使它更早停止(第 34818 行)。

是什么阻止了我的差异?

更新:我的怀疑是,在diff a ba 和 b 很大的地方运行时,diff 会要求 a 中的一堆行,然后是 b 中的一堆。由于辅助脚本只提供并行行,它尝试将一行推送到 a,然后将另一行推送到 b,但 diff 正在从 a 请求更多行,因此推送到 b 挂起。但是,在执行常规diff <(cmd) <(cmd)操作时,第一个 cmd 可以推送一堆行,而第二个则等待。

4

2 回答 2

1

根据您的说明更改答案。

我建议您转储awk并使用perl脚本作为您的助手来完成这项工作。

#!/usr/bin/perl
use strict;
use warnings;

my ($f1 ,$f2)=@ARGV;

open(my $fifo1, '<', $f1) || die("Couldn't open file $f1: $!");
open(my $fifo2, '<', $f2) || die("Couldn't open file $f2: $!");

my $count=0;
while(not (eof($fifo1) or eof($fifo2)) ) {
    my $a = <$fifo1>; chomp($a);
    my $b = <$fifo2>; chomp($b);
    print "my_diffing_function(\'$a\', \'$b\')\n"; 
    # Alternatively write these lines to 2 fifos
    ++$count;
}
close $fifo1;
close $fifo2;

这允许您定义自己的 diff 函数来逐行检查是否存在差异。或者你可以使用Text::Diff来做同样的事情。更好的是,您可以打开 2 个 fifo 来写入并让diff这些 fifo 工作。

要测试它,只需执行以下操作:

samveen@precise:/tmp$ perl differ.pl <(yes |head -n 20) <(yes 'n' |head -n 30)
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')
my_diffing_function('y', 'n')

您可以打开一对管道用于此帮助脚本的输出并将其写出,并在管道的一侧产生差异。

于 2013-06-10T12:55:09.287 回答
0

另一种选择是简单地解析差异输出并删除底部的绒毛。不幸的是,这似乎是最简单的。例如处理 -u 和常规差异输出:

diff "$@" "$if1" "$if2" | awk '
lines && /^@@ -[0-9]*,[0-9]* \+[0-9]*,[0-9]* @@$/ {print lines; lines=""}
lines && /^[0-9]+,[0-9]+d[0-9]+$/ {print lines; lines=""}
// {if(lines)lines=lines"\n"$0; else lines=$0}
'

处理 -y 需要更多的工作。这不是一个非常令人满意的解决方案。

于 2013-06-11T11:43:21.780 回答