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