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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13930074/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:02:20  来源:igfitidea点击:

Sed error: 'unescaped newline inside substitute pattern' and 'bad flag in substitute command'

regexbashshellsedplist

提问by kimimaro

Question:

题:

I am new in sed,so when I excute following code in shell:

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

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

Sed give me an error: "sed: 1: "/^\sCHANNEL_NAME<\ ...": unescaped newline inside substitute pattern"

sed 给我一个错误:"sed: 1: "/^\sCHANNEL_NAME<\ ...": unscaped newline inside替代模式"

My Question: What does "unescaped newline inside substitute pattern" exactly mean?

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

The Info.plist file is like this:

Info.plist 文件是这样的:

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

I am appreciate everyone could answer the question, thanks!

非常感谢大家能回答这个问题,谢谢!



Anwser:

答案:

Thanks @potong @dogbane @Beta ! : )

谢谢@potong @dogbane @Beta!:)

Because it is a Cocoa plist, so here's my finally solution:

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

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

Tips:

提示:

  1. I got two error during my process to solve the problem. Put them here:
    • sed: 1: "/^\sCHANNEL_NAME<\ ...": unescaped newline inside substitute pattern
    • sed: 1: "/CHANNEL_NAME</ke ...": bad flag in substitute command: '}'
  2. I make so many mistakes in the first code.
    • haven't escaped the '+'
    • should end with 2/}"
    • acturally should end with 2/;}" (I miss a ';', so I got the second error in Tips 1)
  3. user 'n' or 'N' both works for me.
  4. Probably because of on Mac, the '.+' (even if I escaped) not work, so have to change it as @potong said, '..*'
  1. 在解决问题的过程中,我遇到了两个错误。把它们放在这里:
    • sed: 1: "/^\sCHANNEL_NAME<\ ...": 替代模式内未转义的换行符
    • sed: 1: "/CHANNEL_NAME</ke ...": 替代命令中的错误标志:'}'
  2. 我在第一个代码中犯了很多错误。
    • 没有逃脱“+”
    • 应该以 2/} 结尾"
    • 实际上应该以 2/;}" 结尾(我错过了一个 ';',所以我在提示 1 中遇到了第二个错误)
  3. 用户 'n' 或 'N' 都适用于我。
  4. 可能是因为在 Mac 上,“.+”(即使我逃脱了)不起作用,所以必须像@potong 所说的那样更改它,“..*”

Any good advice to approve the code is welcome, thanks all the following guys again!

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

回答by potong

This might work for you (GNU sed):

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

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

N.B. You should allow for whitespace (^\s*) at the beginning of a line and print the matched line before comparing the start of the next line for the substitution command i.e. use ninstead of N.

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

Or:

或者:

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

回答by Ed Morton

Since you said you're just learning sed: sed is an excellent tool for simple substitutions on a single line but for anything else just use awk.

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

Here's a GNU awk solution (you can cram it onto one line if you like):

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

$ cat file
...
foo
<key>CHANNEL_NAME</key>
<string>App Store</string>
...
$
$ awk '
   found { 
$ awk '
   found { 
awk '
   found { ##代码##=gensub(/(<string>).*(<\/string>)/,"\1" rep "\2",""); found=0 }
   /<key>CHANNEL_NAME<\/key>/ { found=1; rep=prev }
   { print ##代码##; prev=##代码## }
' file
...
foo
<key>CHANNEL_NAME</key>
<string>foo</string>
...
=gensub(/(<string>).*(<\/string>)/,"\1test\2",""); found=0 } /<key>CHANNEL_NAME<\/key>/ { found=1 } { print NR, ##代码## } ' file 1 ... 2 foo 3 <key>CHANNEL_NAME</key> 4 <string>test</string> 5 ...
=gensub(/(<string>).*(<\/string>)/,"\1test\2",""); found=0 } /<key>CHANNEL_NAME<\/key>/ { found=1 } { print ##代码## } ' file ... foo <key>CHANNEL_NAME</key> <string>test</string> ...

It doesn't LOOK much different from the sed solution, but just try modifying the sed solution to do anythingadditional e.g. add line numbers to the output:

它看起来与 sed 解决方案没有太大不同,但只需尝试修改 sed 解决方案以执行任何其他操作,例如向输出添加行号:

##代码##

or replace the text between "string"s with the contents of the line before CHANNEL_NAME instead of the hard-coded "test":

或者用 CHANNEL_NAME 之前的行的内容替换“string”之间的文本,而不是硬编码的“test”:

##代码##

and you'll find you need a whole other solution, probably involving a nightmarish concoction of single letters and punctuation marks, whereas with awk it's a simple tweak to enhance your starting solution.

并且您会发现您需要一个完整的其他解决方案,可能涉及单个字母和标点符号的噩梦般的组合,而使用 awk,这是一个简单的调整,可以增强您的初始解决方案。