用一定数量替换数字范围

时间:2015-07-11 17:37:39

标签: bash awk sed grep

我需要用一定数量的数字替换一系列数字。我真的很难用sed编写代码(比如sed“s / [33-64] / 64 /”)或awk,但总是得到错误的结果。它倾向于替换单个数字而不是数字...我需要的是:替换0-32 - > 32,33-64 - > 64,65-128 - > 128,129-255 - > 255.在这些数字之间是IP,这应该保持不变。我认为这个命令选择了所有,但IP:

sed '/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/! ...  '

所以我有一个这样的文件:

65.74.16.161
232
10.128.8.72
63
10.128.14.13
100
10.128.8.58
32
10.128.4.129
60
10.128.240.18
59

它应该是这样的:

65.74.16.161
255
10.128.8.72
64
10.128.14.13
128
10.128.8.58
32
10.128.4.129
64
10.128.240.18
64

3 个答案:

答案 0 :(得分:3)

[33-64]定义了一个字符类,是一种写[3-6]的有趣方式,确实只匹配一个字符 - 来自3,4,5或6的任何单个数字。如果你真的想要使用sed执行此操作,并且您关注的是33到64之间的值,那么您必须以不同的方式编写它 - 并且更加冗长。

部分取决于您拥有的sed版本。适用于经典sed的解决方案是:

sed -e 's/^[0-9]$/32/' \
    -e 's/^[12][0-9]$/32/' \
    -e 's/^3[012]$/32/' \
    -e 's/^3[3-9]$/64/' \
    -e 's/^[45][0-9]$/64/' \
    -e 's/^6[0-4]$/64/' \
    -e 's/^6[5-9]$/128/' \
    -e 's/^[7-9][0-9]$/128/' \
    -e 's/^1[01][0-9]$/128/' \
    -e 's/^12[0-8]$/128/' \
    -e 's/^129$/255/' \
    -e 's/^1[3-9][0-9]$/255/' \
    -e 's/^2[0-4][0-9]$/255/' \
    -e 's/^25[0-5]$/255/'

但是,正如你所看到的,这是非常痛苦的。如果您有GNU sed,则可以使用-r选项启用扩展正则表达式;如果您使用的是Mac OS X或BSD sed,则可以使用-E选项启用扩展正则表达式。然后,您可以将上面的代码缩减为:

sed -E \
    -e 's/^([0-9]|[12][0-9]|3[012])$/32/' \
    -e 's/^(3[3-9]|[45][0-9]|6[0-4])$/64/' \
    -e 's/^(6[5-9]|[7-9][0-9]|1[01][0-9]|12[0-8])$/128/' \
    -e 's/^(129|1[3-9][0-9]|2[0-4][0-9]|25[0-5])$/255/'

但是,使用awk

可能会做得更好
awk '/^[0-9][0-9]*$/ { if      ($1 <=  32) print  32
                       else if ($1 <=  64) print  64
                       else if ($1 <= 128) print 128
                       else if ($1 <= 255) print 255
                       else                print  $1
                       next
                     }
     { print }'

最终的else子句准确地打印出任何意外的值,例如256或999,或者实际上是123456789.有些人会用1来代替{ print } - 部分匹配并打印IP地址的awk脚本。

答案 1 :(得分:1)

您可以使用此awk进行一些算术运算:

awk '$1 == ($1+0) && $1<=255{$1 = ($1>128)?255:($1>64?128:32 * int(($1+31)/32))} 1' file
65.74.16.161
255
10.128.8.72
64
10.128.14.13
128
10.128.8.58
32
10.128.4.129
64
10.128.240.18
64

$1 == ($1+0)是一项检查,用于确定$1是一个整数。

答案 2 :(得分:0)

使用awk:

awk -vFS=. ' NF == 1 { v=2^int((log($1)/log(2))+0.5); $1 = v>255?255:v; }1' input

给出:

65.74.16.161
255
10.128.8.72
64
10.128.14.13
128
10.128.8.58
32
10.128.4.129
64
10.128.240.18
64