使用sed在bash中查找并替换其后续数字

时间:2017-11-13 13:14:09

标签: linux bash sed operators

我有一个字符串,其中包含多个出现的数字范围,用逗号分隔,例如

2-12,59-89,90-102,103-492,593-3990,3991-4930

现在我想删除所有直接相邻的范围并将其从字符串中删除,即删除-(x),(x+1)形式的任何内容,以获得类似的内容:

2-12,59-492,593-4930

有人能想到一种方法来实现这个目标吗?老实说,我不会发布任何我尝试过的东西,因为我的所有尝试都非常不成功。对我来说,似乎不可能使用sed实际找到-(x),(x+1)形式的任何内容,因为这需要对另一个数字进行操作或比较找到的数字,该数字必须是当前命令的一部分寻找数字。

如果每个人都同意sed不是这样做的正确工具,我会采取另一种方式,但我仍然感兴趣,如果可能的话。

3 个答案:

答案 0 :(得分:4)

awk

awk -F, -v RS="-" -v ORS="-" '$2!=$1+1' file

使用适当的分隔符设置,在第二个字段不是+1时打印记录。

RS是记录分隔符,ORS是分页记录分隔符。

试验:

> awk -F, -v RS="-" -v ORS="-"
 '$2!=$1+1' <<< "2-12,59-89,90-102,103-492,593-3990,3991-4930"

2-12,59-492,593-4930

答案 1 :(得分:2)

awk 解决方案:

awk -F'-' '{   r=$1; 
               for (i=2; i<=NF; i++) { 
                   split($i, a, ","); 
                   r=sprintf("%s%s", r, a[2]-a[1]==1? "" : FS $i) 
               } 
               print r 
           }' file
  • -F'-' - 将-(连字符)视为字段分隔符
  • r - 结果字符串
  • split($i, a, ",") - 通过分隔符a
  • 将相邻的范围边界拆分为数组,
  • a[2]-a[1]==1 - 关键条件,反映(x),(x+1)

输出:

2-12,59-492,593-4930

答案 2 :(得分:1)

这可能适合你(GNU sed):

sed -r ' s/^/\n/;:a;ta;s/\n([^-]*-)([0-9]*)(.*,)/\1\n\2\n\2\n\3/;Td;:b;s/(\n.*\n.*)9(_*\n)/\1_\2/;tb;s/(\n.*\n)(_*\n)/\10\2/;s/$/\n0123456789/;s/(\n.*\n[0-9]*)([0-8])(_*\n.*)\n.*\2(.).*/\1\4\3/;:z;tz;s/(\n.*\n[^_]*)_([^\n]*\n)/\10\2/;tz;:c;tc;s/([0-9]*-)\n(.*)\n(.*)\n,(\3)-/\n\1/;ta;s/\n(.*)\n.*\n,/\1,\n/;ta;:d;s/\n//g' file

这种概念验证sed解决方案,迭代地递增并将一个范围的结束与另一个范围的开始进行比较。如果比较为真,则删除两者并重复,否则它将移至下一个范围并重复,直到比较所有范围。