替换同一行上的图案范围之间的文本

时间:2017-04-28 19:20:36

标签: bash awk sed

对于awk而言,这可能比sed更好,但目标是解析单个长字符串(恰好是XML文档)并替换模式范围内的文本另一个角色。

我想保留被替换的字符数,并简单地将它们掩盖为星号。我在python脚本中放了一些东西来解析XML树,但感觉本机程序会更快。

假设字符串:"<mask>123</mask><keep>123</keep>"

...我想要输出:"<mask>***</mask><keep>123</keep>"

我第一次尝试sed而不使用范围让我这样:

$ echo "<mask>123</mask><keep>123</keep>" | sed "s/[0-9]/*/g"
<mask>***</mask><keep>***</keep>

我了解到sed可以在范围内操作,但我的理解是行为只能从一行到另一行切换,而不是在处理单行的过程中。

尝试模式范围让我得到以下(与我的理解一致),因此也无效:

$ echo "<mask>123</mask><keep>123</keep>" | sed "/<mask>/,/<\/mask>/ s/[0-9]/*/g" 
<mask>***</mask><keep>***</keep>

编辑:事实上,即使输入中有换行符,我也不能正确理解模式范围行为(或者我的例子构造不当)

$ echo "<mask>123</mask>\n<keep>123</keep>" | sed "/<mask>/,/<\/mask>/ s/[0-9]/*/g" 
<mask>***</mask>
<keep>***</keep>

任何提示都将不胜感激。

2 个答案:

答案 0 :(得分:2)

永远不要使用范围表达式,因为它们使简单任务变得非常简单,但是当您的需求变得稍微有点时需要完全重写或重复条件,如果需要范围,请始终使用标志变量。当然,这意味着您不能将sed用于此类问题,因为它不支持变量。

无论如何,这里有一个简单的GNU awk(用于多字符RS和RT)解决方案,它根本不直接使用范围:

$ cat file
Assuming the string: "<mask>123</mask><keep>123</keep>" ...I'd like the

$ awk -v RS='</mask>' -v ORS= '{print gensub(/(.*<mask>).*/,"\\1***",1) RT}' file
Assuming the string: "<mask>***</mask><keep>123</keep>" ...I'd like the

或者如果您需要*的数量来匹配他们要替换的字符数:

$ cat file
Assuming  first string: "<mask>123</mask><keep>123</keep>" ...I'd like the
Assuming second string: "<mask>1234567</mask><keep>123</keep>" ...I'd like the

$ awk -v RS='</mask>' 'match($0,/(.*<mask>)(.*)/,a){ $0=a[1] gensub(/./,"*","g",a[2]) } {ORS=RT} 1' file
Assuming  first string: "<mask>***</mask><keep>123</keep>" ...I'd like the
Assuming second string: "<mask>*******</mask><keep>123</keep>" ...I'd like the

答案 1 :(得分:1)

为什么你得到这个输出是完全正确的。这是两个正则表达式的sed范围地址的技巧。

你给sed的内容是/regex1/, /regex2/,sed将首先尝试找到与address1匹配的行,/regex1/,第一行匹配,很好。那么你的address2也是正则表达式,所以:

  

如果addr2是正则表达式,则不会对该行进行测试   addr1匹配。

这句话来自sed的手册页。

也就是说,sed开始从第2行检查你的/regex2/。当然,没有一行与/<\/mask>/匹配,所以sed只是对整个文件进行了替换。

检查此示例:

kent$  cat f
<mask>234</mask>
123
123
123
<mask>234</mask>
123
123
<keep>234</keep>

kent$  sed "/<mask>/,/<\/mask>/ s/[0-9]/*/g" f
<mask>***</mask>
***
***
***
<mask>***</mask>
123
123
<keep>234</keep>

最后只是一个建议,不要用正则表达式处理xml(sed / awk / grep ...)。当然,您可以只使用“xml”作为示例。