使用sed根据正则表达式结果

时间:2016-02-25 17:31:38

标签: linux bash sed

我需要阅读日志文件并查找文本<KEY>any_number_here</KEY><KEYVAL>any_number_hereDany_number_here</KEYVAL>并替换这些数字,使其如下所示:

<KEY>*************5683</KEY><KEYVAL>*************5683D00000000000000000000</KEYVAL>

这是日志行的一个示例:

2016/02/01 04:20:21 [18f][00000000000001526][0][00000000000000] Some text here: [size: 000 communication_format: ISO0000 data: "<Document xmlns='bla'><KEY>44444444444445683</KEY><DATE>2017-05</DATE><DATA>2</DATA><KEYVAL>44444444444445683D00000000000000000000</KEYVAL>"]

请注意<{1}}上的 D 分隔值。

这是我第一次尝试<KEYVAL>,我可以在sed标记内获取值,但我不知道如何处理该值并用{{替换部分值1}}

我只有表达式来获取<KEY>标记内的内容:

*

更新 现在我有了这个解决方案,这是我得到的最接近的东西:

<KEY>

问题在于它正在用sed -e 's/<KEY>\([[:digit:]]*\)<\/KEY>/ANOTHER SUBSTITUTION HERE?/' test.log 替换它找到的任何sed -e 's/<KEY>[[:digit:]]\{13\}/(&)/g' -e 's/(.*)/<KEY>*************/g' pan.txt ,并且日志文件中有几个()

更新2

我想我找到了解决方案:

<KEY>*************

这仅适用于()代码。

2 个答案:

答案 0 :(得分:2)

作为一个单行:

$ sed -r ':a;s|(<KEY>\**)[0-9]([0-9]*[0-9]{4}</KEY>)|\1*\2|;s|(<KEYVAL>\**)[0-9]([0-9]*[0-9]{4}D[^<]*</KEYVAL>)|\1*\2|;ta' <<< "$var"
2016/02/01 04:20:21 [18f][00000000000001526][0][00000000000000] Some text here: [size: 000 communication_format: ISO0000 data: "<Document xmlns=bla><KEY>*************5683</KEY><DATE>2017-05</DATE><DATA>2</DATA><KEYVAL>*************5683D00000000000000000000</KEYVAL>"]

这可以处理任意数量的数字,并且总是留下最后四位数。为了实现这种灵活性,命令的整体结构如下:

:label   # Label to branch to
s///     # Substitute one digit for <KEY>
s///     # Substitute one digit for <KEYVAL>
t label  # If a substitution took place, branch back to 'label'

因此,只要任何替换做了某些事情,我们就会循环回来并尝试使用t命令替换另一个数字(条件分支)。

现在,对于替换,它们看起来如下:

s|(<KEY>\**)[0-9]([0-9]*[0-9]{4}</KEY>)|\1*\2|

这使用了两个捕获组:一个包含<KEY>,但后面有许多*。然后是一个未捕获的数字(我们将在此循环中替换),然后是由[0-9]*[0-9]{4}</KEY>组成的第二个捕获组,即以四位数字</KEY>结尾的任意数量的数字。替换只是用星号替换未捕获的数字。

请注意,我使用扩展正则表达式(-r选项),因此我不必转义(),并且管道|作为分隔符,所以我不必逃避/

第二次替换几乎相同:

s|(<KEYVAL>\**)[0-9]([0-9]*[0-9]{4}D[^<]*</KEYVAL>)|\1*\2|

唯一的区别是,它会查找KEYVAL而不是KEY,并且在结束标记和要保留的四位数之间会有D[^<]*,即{{1}跟随开头尖括号以外的任意数量的字符。

没有循环的替代解决方案

绝对没有单行内容,但对于大型日志文件可能更快:

D

这必须存储在一个单独的文件中(某些seds不喜欢这些注释,因此可以删除它们)然后像这样调用:

h        # Copy pattern space to hold space

# Remove everything except digits we want to replace from pattern space
s|.*<KEY>(.*)[0-9]{4}</KEY>.*|\1|

s/./*/g  # Replace digits with '*'
G        # Append hold space to pattern space

# Rearrange pattern space
s|(.*)\n(.*<KEY>).*([0-9]{4}</KEY>.*)$|\2\1\3|

# And the the same for the KEYVAL part
h
s|.*<KEYVAL>(.*)[0-9]{4}D.*</KEYVAL>.*|\1|
s/./*/g
G
s|(.*)\n(.*<KEYVAL>).*([0-9]{4}D.*</KEYVAL>.*)$|\2\1\3|

答案 1 :(得分:1)

$cat inputfile 
2016/02/01 04:20:21 [18f][00000000000001526][0][00000000000000] Some text here: [size: 000 communication_format: ISO0000 data: "<Document xmlns='bla'><KEY>44444444444445683</KEY><DATE>2017-05</DATE><DATA>2</DATA><KEYVAL>44444444444445683D00000000000000000000</KEYVAL>"]

$ egrep -o -e '<KEY>[0-9]+</KEY>' -e '<KEYVAL>[0-9]+D[0-9]+</KEYVAL>' inputfile | sed -r -e 's/^(<KEY>.*)([0-9]{4})(<\/KEY>)$/\1\n\2\3/g;' -e 's/^(<KEYVAL>.*)([0-9]{4}D[0-9]+)(<\/KEYVAL>)$/\1\n\2\3/g' | sed -e '1~2 s/[0-9]/*/g' | sed -n 'N;s/\n//g;p'
<KEY>*************5683</KEY>
<KEYVAL>*************5683D00000000000000000000</KEYVAL>

它处理KEY中5683之前的任意位数,也处理KEYVAL中5683D之前和之后的任意位数。 5683也可以是任意4位数。