差异两个流(使用fifo)直到一个结束 - 仅适用于短流

时间:2013-06-10 10:41:52

标签: bash diff fifo

我想要一个diff包装器,我可以在任意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用dhdiff传递给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

Complete script

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

的话
mindiff <(yes |head -40000) <(yes |head -40000)
它只是挂起。添加“打印NR;”到awk显示它上线 36865(与<(yes yesyes)同时为10533,所以似乎是 允许一定数量的字节,无论行数如何。)

添加system("")以刷新每行的awk使其更早停止 (第34818行)。

什么阻挡了我的差异?

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

2 个答案:

答案 0 :(得分: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')

你可以打开一对管道来输出这个助手脚本并写出来,然后在管道的一侧产生差异。

答案 1 :(得分:0)

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

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需要更多的工作。这不是一个非常令人满意的解决方案。