我需要读取一个日志文件,查找文本<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>"]

注意<KEYVAL>上的d分隔值。
这是我第一次尝试sed并且我可以得到<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

问题是它正在用()替换找到的任何<KEY>*************,日志文件中有几个()
更新2
我想我找到了解决办法:
sed -e 's/<KEY>[[:digit:]]\{13\}/(&)/g' -e 's/(.*)/<KEY>*************/g' pan.txt

这只适用于KEY标记。

最佳答案

作为一行:

$ 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,即aD[^<]*后跟除开始尖括号之外的任意数量的字符。
无循环的替代解决方案
绝对没有一行材料,但对于大型日志文件来说可能更快:
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|

这必须存储在一个单独的文件中(有些sed不喜欢注释,因此可以删除它们),然后按如下方式调用:
$ sed -rf sedscr.sed <<< "$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>"]

关于linux - 使用sed根据正则表达式结果替换部分文本,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35634260/

10-16 20:46