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

时间:2012-12-18 09:40:33

标签: regex bash shell sed plist

问题:

我是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&lt; \ ...“:替换模式中未转义的换行符”

我的问题:“替代模式中未转义的换行符”究竟意味着什么?

Info.plist文件是这样的:

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

我很感激大家都能回答这个问题,谢谢!


Anwser:

谢谢@potong @dogbane @Beta! :)

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

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

提示:

  1. 我在解决问题的过程中遇到两个错误。把它们放在这里:
    • sed:1:“/ ^ \ sCHANNEL_NAME&lt; \ ...”:替换模式中未转义的换行符
    • sed:1:“/ CHANNEL_NAME&lt; / ke ...”:替换命令中的错误标志:'}'
  2. 我在第一段代码中犯了很多错误。
    • 没有逃过'+'
    • 应以2 /}“
    • 结尾
    • 当然应该以2 /;}结尾“(我想念一个';',所以我在提示1中得到了第二个错误)
  3. 用户'n'或'N'都适合我。
  4. 可能是因为在Mac上,'。+'(即使我逃脱)不起作用,所以必须改变它,因为@potong说,'.. *'
  5. 欢迎任何批准该代码的好建议,再次感谢以下所有人!

2 个答案:

答案 0 :(得分:4)

这可能适合你(GNU sed):

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

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

或者:

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

答案 1 :(得分:1)

既然你说你刚刚学习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 ...

或将“string”之间的文字替换为CHANNEL_NAME之前的行内容而不是硬编码的“test”:

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这是一个简单的调整来增强你的起始解决方案。