使用sed更改标记之间的文本

时间:2015-05-15 10:14:20

标签: macos sed

我无法弄清楚如何在mac上使用sed将文件CHANGEME中的CHANGED更改为myFile.xml

<string name="myTag">CHANGEME</string>

我试过了:

sed -i -e "s/\(<string name=\"myTag\">\)\(<\/string>\)/\1CHANGED\2/g" ./myfile.xml

但输出只是沉默。 有什么帮助吗?

3 个答案:

答案 0 :(得分:3)

您与<string</string>之间的阻止不匹配。例如,使用[^<]*来查找找到<之前的所有内容:

$ sed -e 's/\(<string name="myTag">\)[^<]*\(<\/string>\)/\1CHANGED\2/g' file
<string name="myTag">CHANGED</string>

根据Dipak的建议,如果CHANGED<string>标记中没有文字,您可能希望避免撰写</string>。如果是这样,您可以说[^<]+以确保找到至少一个字符:

$ cat a
<string name="myTag">CHANGEME</string>
<string name="myTag"></string>
$ sed -e 's/\(<string name="myTag">\)[^<]\+\(<\/string>\)/\1CHANGED\2/g' a
<string name="myTag">CHANGED</string>
<string name="myTag"></string>

答案 1 :(得分:3)

有两个问题:

  • 您正在使用 GNU Sed语法:在 BSD Sed中,这是OSX上使用的版本,-i 需要和参数,即使它是空字符串(表示应该创建 no 备份),所以必须使用-i '' (请注意,由于技术原因,-i'' 工作。)

    • 有关GNU和BSD Sed之间差异的概述,请参阅here
  • 您未匹配元素as fedorqui points out in his helpful answer内容

    • 但是,他的正则表达式使用 GNU 语法:quantier \+(对于一个或多个匹配)支持 BSD Sed。
    • 虽然您可以通过将\+替换为符合POSIX的\{1,\}来轻松解决此问题,但我建议您使用扩展正则表达式代替-E - 请参阅下方。

除非你必须保持真正的POSIX兼容(在这种情况下你甚至不能使用-i),我通常建议使用-E激活对扩展正则表达式的支持的选项

  • 扩展正则表达式功能更强大,更像您可能习惯使用其他语言(尤其是+?|);值得注意的是:
  • 语法变得更清晰(无需\ - 转义字符。例如(){})。

一个很好的例子:这里使用-E 修改了您的命令版本:

sed -i '' -E 's/(<string name="myTag">)[^>]+(<\/string>)/\1CHANGED\2/g' ./myfile.xml

请注意,我已经切换到围绕Sed脚本的 单个引号,这也是通常更好的选择

  • 您可以通过shell保护脚本免受可能不需要的前期解释(扩展)。
  • 您不必\ - 逃离"个实例。

答案 2 :(得分:1)

这应该是评论,但由于我没有获得特权,我在这里发帖

Fedorqui建议的代码完全正常并将 CHANGEME 更改为已更改但是,如果标记之间没有任何内容,则会插入已更改

如果要求将空标记保留为空,则可以按如下方式修改代码:

sed 's/\(<string name="myTag">\)[^<].*\(<\/string>\)/\1CHANGED\2/g'

sed 's/\(<string name="myTag">\)..*\(<\/string>\)/\1CHANGED\2/g' file

在第1种情况下,它会搜索<string name="myTag">,然后搜索不以<开头,后跟0次或更多次的内容,并将其替换为已更改。案例2搜索<string name="myTag">后跟至少一个字符,并将其替换为已更改