1

问题:

我是 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

尖端:

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

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

4

2 回答 2

4

这可能对您有用(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
于 2012-12-18T11:48:37.053 回答
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 ...

或将“字符串”之间的文本替换为 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 它是一个简单的调整来增强你的起始解决方案。

于 2012-12-19T13:41:09.383 回答