sed:替换用单引号包围的中间数字模式

时间:2018-04-02 12:35:19

标签: linux shell sed grep

我有数百个包含以下文本类型的xml文件

Exception Domains

其中 max_value 元素可能具有不同的值。

问题:我需要在所有文件中将max_value元素的值替换为100(例如)。我尝试过像下面这样的事情。

<Init dflt_value='1.00' max_value='1000000.00' diff_ele='1.0' new='Yes' />

但没有什么对我有用。 它可能是什么解决方案?

3 个答案:

答案 0 :(得分:1)

不要使用正则表达式解析XML / HTML,使用正确的XML / HTML解析器和强大的查询。

理论:

  

根据编译理论,无法使用基于finite state machine的正则表达式解析XML / HTML。由于XML / HTML的层次结构,您需要使用pushdown automaton并使用LALR等工具操作YACC语法。

中的realLife©®™日常工具:

您可以使用以下其中一项:

xmllint通常默认使用libxml2,xpath1安装(检查my wrapper以使换行符分隔输出

xmlstarlet可以编辑,选择,转换......默认情况下不安装,xpath1

通过perl的模块XML :: XPath,xpath1

安装

xpath

xidel xpath3

saxon-lint我自己的项目,包装在@Michael Kay的Saxon-HE Java库中,xpath3

或者您可以使用高级语言和正确的库,我想:

lxmlfrom lxml import etree

XML::LibXMLXML::XPathXML::Twig::XPathHTML::TreeBuilder::XPath

check this example

DOMXpathcheck this example

检查:Using regular expressions with HTML tags

使用的示例:

xmlstarlet ed -u '//Init/@max_value' -v '100' *.xml

如果您要编辑 ,请使用-L开关:

xmlstarlet ed -L -u '//Init/@max_value' -v '100' *.xml

使用&amp;的示例来编辑到位

# edit in place XML
from lxml import etree
import sys
myXML = sys.argv[1]

tree = etree.parse(myXML)
root = tree.getroot()
code = root.xpath("//Init")
for i in code:
    if (i.attrib['max_value']):
        i.attrib['max_value'] = '100'

etree.ElementTree(root).write(myXML, pretty_print=True)

答案 1 :(得分:1)

你的具体问题是,在sed中,.*是“贪婪的”。也就是说,它尽可能地匹配 ,这可能导致它将两个或多个字段合并为一个。

你想要对你的比赛更加小心。要替换数字,请尝试只匹配数字,可能是小数点:

s/max_value='[0-9.]*'/max_value='25'/g

通常,您要做的是使用结束引号的否定字符类:

s/'[^']*'/ ...

但是在这个特定的情况下,0-9完成了这项工作,并且稍微清楚一些。 (您不希望尝试使用这种方式使用正模式匹配句子中的每个可能字符 - 使用负模式更好,只说“除了结束引号之外的所有内容,然后是结束引用”。

答案 2 :(得分:1)

问题是您在' subexpr中包含.*个字符。更好用:

xargs sed "/max_value=/s/max_value='[^']*'/max_value='${new_value}'/g"

注释

请注意'是shell的特殊字符(所以我在整个sed命令周围使用双引号)

还要考虑到表达式不仅可以出现在您正在搜索的位置。由于XML不是常规的,因此用匹配的正则表达式解析它并不是一个好主意。使用完整的XML解析器将允许您以xml属性为基础更改所有实例,而不是纯文本搜索。并且考虑到grep(1)是一个过滤器,您不会编辑文件,您将在标准输出上获得该文件。

如果要编辑文件,可以使用ed(1)代替。

grep -rl max_value . |
while read file
do
    ed file <<EOF
    1,$s/max_value='[^']'/max_value='100'/g
    w
    q
EOF
done