将连续数字组合成unix中的间隔

时间:2013-09-15 05:34:28

标签: unix ksh

我在a.txt文件中输入了

10000030
10000029
10000028
10000027
10000026
10000024
10000023
10000021
10000018
10000018
10000017
10000016
10000015
10000014
10000013
10000011
10000010
10000009
10000008
10000006
10000005
10000004
10000003
10000002
10000001

我需要将连续的输入组合在一起,例如:

10000001,10000006,6
10000008,10000011,4
10000013,10000019,7
10000021,10000021,1
10000023,10000024,2
10000026,10000030,5

帮我解决这个脚本.....

1 个答案:

答案 0 :(得分:2)

首先,您的输入数据似乎有拼写错误。为了获得您想要的输出,首先10000018应为10000019

修复后,您可以通过以下awk脚本传递已排序的文件来获得所需的输出:

NR==1 {
    first = $0;
    last = $0;
    prev = $0;
    count = 1;
    next;
}
$0 == prev+1 {
    last = $0;
    prev = $0;
    count++;
    next;
}
{
    print first","last","count;
    first = $0;
    last = $0;
    prev = $0;
    count = 1;
}
END {
    if (count > 0) {
        print first","last","count
    }
}

调用该脚本data.awk并将您的数据放入data.in,结果如下:

pax> sort data.in | awk -f data.awk
10000001,10000006,6
10000008,10000011,4
10000013,10000019,7
10000021,10000021,1
10000023,10000024,2
10000026,10000030,5

阐述awk脚本的工作原理。对于第一个输入行NR == 1,它只是将当前值存储到firstlastprev(序列的开头,序列的结尾和前一个)用于监控序列的行。它还将当前计数设置为1,然后返回处理第二行。

在所有后续行中,如果当前行比前一行多一个,则会触发第二部分$0 == prev+1。在这种情况下,它只是更新lastprev值并递增count,然后返回到顶部以处理下一行。

因此,第三部分将触发前两部分未捕获的任何情况。这是输入文件中除第一行以外的任何记录,其中行不是一行加上前一行。换句话说,当开始新序列时。它首先打印出最新序列的详细信息,然后复制我们在第一部分中所做的内容。

处理完所有行后,END部分将触发,输出最终序列的详细信息。请注意,仅当count大于零时才输出。如果count 为零,那么该文件为空,因此根本没有序列。


还有一个略短的变体,它依赖于一些额外的条件,连接线条,以及这些部分按顺序处理的事实:

NR > 1 && $0 == prev+1 {
    last = $0; prev = $0; count++;
    next;
}
{
    if (NR != 1) { print first","last","count; }
    first = $0; last = $0; prev = $0; count = 1;
}
END {
    if (count > 0) { print first","last","count }
}

当然,超短(且可读性差)命令行变量:

pax> sort data.in | awk 'NR>1&&$0==pr+1{ls=$0;pr=$0;ct++;next}{if(NR!=1){print fr","ls","ct}fr=$0;ls=$0;pr=$0;ct=1}END{if(ct>0){print fr","ls","ct}}'
10000001,10000006,6
10000008,10000011,4
10000013,10000019,7
10000021,10000021,1
10000023,10000024,2
10000026,10000030,5