首先,您的输入数据似乎有错字。为了获得您想要的输出,首先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
,它只是将当前值存储到first
,last
和prev
(序列的开始、序列的结束和用于监视序列的前一行。它还将当前计数设置为1
并返回处理第二个线。
$0 == prev+1
在所有后续行中,如果当前行比上一行多一个,则触发第二部分。在这种情况下,它只是更新last
和prev
值和增量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