Sed 错误:“替代模式内未转义的换行符”和“替代命令中的错误标志”

Posted

技术标签:

【中文标题】Sed 错误:“替代模式内未转义的换行符”和“替代命令中的错误标志”【英文标题】:Sed error: 'unescaped newline inside substitute pattern' and 'bad flag in substitute command' 【发布时间】:2012-12-18 09:40:32 【问题描述】:

问题:

我是sed新手,所以当我在shell中执行以下代码时:

sed -e "/^\s<key>CHANNEL_NAME<\/key>$/N;s/\(^\s<string>\).+\(<\/string>$\)/\1test\2" Info.plist > test.plist

Sed 给我一个错误:“sed: 1: "/^\sCHANNEL_NAME

我的问题:“替代模式内未转义的换行符”到底是什么意思?

Info.plist 文件是这样的:

...
<key>CHANNEL_NAME</key>
<string>App Store</string>
...

感谢大家回答问题,谢谢!


回答者:

感谢@potong @dogbane @Beta! :)

因为它是一个 Cocoa plist,所以这是我的最终解决方案:

sed '/<key>CHANNEL_NAME<\/key>/N;s/\(<string>\).*\(<\/string>\)/\1test\2/;' Info.plist > test.plist

提示:

    我在解决问题的过程中遇到了两个错误。把它们放在这里: sed: 1: "/^\sCHANNEL_NAME sed: 1: "/CHANNEL_NAME...": 替换命令中的错误标志:'' 我在第一个代码中犯了很多错误。 没有逃脱'+' 应该以 2/" 结尾 实际上应该以 2/;" 结尾(我错过了一个 ';',所以我在提示 1 中遇到了第二个错误) 用户“n”或“N”都适用于我。 可能是因为在 Mac 上,'.+'(即使我逃脱了)不起作用,所以必须按照@potong 所说的那样更改它,'..*'

欢迎任何好的建议来批准代码,再次感谢以下所有人!

【问题讨论】:

我无法重现此错误。但是您的 sed 表达式还有其他问题。您还没有逃脱 + 并且缺少一个斜杠来终止 s 命令,即它应该以 2/" 结尾。 @dogbane 非常感谢。这是一个错误的输入,但问题不是表达。恩,你的操作系统是什么? Linux 还是 Mac? 可以重现错误(在 Mac 上),当我更正 + 并使用 2/; 终止命令时,替换工作。 【参考方案1】:

这可能对你有用(GNU sed):

sed -e '/^\s*<key>CHANNEL_NAME<\/key>$/n;s/^\(\s*<string>\).\+\(<\/string>\)$/\1test\2/' Info.plist > test.plist

注意您应该在行的开头允许空格 (^\s*) 并在比较替换命令的下一行的开头之前打印匹配的行,即使用 n 而不是 N

或者:

sed -e '/^ *<key>CHANNEL_NAME<\/key>$/!b' -e 'n' -e 's/^\( *<string>\)..*\(<\/string>\)$/\1test\2/' Info.plist > test.plist

【讨论】:

我尝试了您的建议,但仍然无法做到。我认为这可能是因为 Mac OS,但不确定。感谢所有的保存 @kimimaro 我添加了一个更通用的解决方案(删除了\s\+ 元字符)。但是,这不考虑标签。 你的回答很有用!因为我的上下文是一个可可plist,所以可能最接近的答案是我自己的问题之后的答案,但你已经解决了我的问题。谢谢!【参考方案2】:

既然您说您只是在学习 sed:sed 是一个出色的工具,可以在单行上进行简单替换,但对于其他任何事情,只需使用 awk。

这是一个 GNU awk 解决方案(如果你愿意,你可以把它塞进一行):

$ cat file
...
foo
<key>CHANNEL_NAME</key>
<string>App Store</string>
...
$
$ awk '
   found  $0=gensub(/(<string>).*(<\/string>)/,"\\1test\\2",""); found=0 
   /<key>CHANNEL_NAME<\/key>/  found=1 
    print $0 
' file
...
foo
<key>CHANNEL_NAME</key>
<string>test</string>
...

它看起来与 sed 解决方案没有太大区别,但只需尝试修改 sed 解决方案来做 任何事情 额外的,例如在输出中添加行号:

$ awk '
   found  $0=gensub(/(<string>).*(<\/string>)/,"\\1test\\2",""); found=0 
   /<key>CHANNEL_NAME<\/key>/  found=1 
    print NR, $0 
' file
1 ...
2 foo
3 <key>CHANNEL_NAME</key>
4 <string>test</string>
5 ...

或将“字符串”之间的文本替换为 CHANNEL_NAME 之前的行的内容,而不是硬编码的“测试”:

awk '
   found  $0=gensub(/(<string>).*(<\/string>)/,"\\1" rep "\\2",""); found=0 
   /<key>CHANNEL_NAME<\/key>/  found=1; rep=prev 
    print $0; prev=$0 
' file
...
foo
<key>CHANNEL_NAME</key>
<string>foo</string>
...

你会发现你需要一个完全不同的解决方案,可能涉及单个字母和标点符号的噩梦般的混合,而使用 awk 是一个简单的调整来增强你的初始解决方案。

【讨论】:

以上是关于Sed 错误:“替代模式内未转义的换行符”和“替代命令中的错误标志”的主要内容,如果未能解决你的问题,请参考以下文章

在 Solaris 上替代 `sed -i`

文本处理工具——sed进阶

perl替代sed分裂多个|

Pyp–一个替代sed,awk的文本处理工具

作为sed替代方案的Perl就地替换

sed与正则用法收集