bash SED 坏替换错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7157921/
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 00:38:35  来源:igfitidea点击:

SED bad substitution error

bashshellsed

提问by Patrick

Here's my problem, I have written the following line of code to format properly a list of files found recursively in a directory.

这是我的问题,我编写了以下代码行来正确格式化在目录中递归找到的文件列表。

find * | sed -e '/\(.*\..*\)/ !d' | sed -e "s/^.*/${File} ${INST\_FILES} &/" | sed -e "s/\( \)\([a-zA-Z0-9]*\/\)/\//" | sed -e "s/\(\/\)\([a-zA-Z0-9\_\-\(\)\{\}$]*\.[a-zA-Z0-9]*\)/ /"

The second step is to write the output of this command in a script. While the code above has the expected behavior, the problem occurs when I try to store its output to a variable, I get a bad substitution error from the first sed command in the line.

第二步是将这个命令的输出写在一个脚本中。虽然上面的代码具有预期的行为,但当我尝试将其输出存储到变量时会出现问题,我从该行中的第一个 sed 命令中得到一个错误的替换错误。

#!/bin/bash
nsisscript=myscript.sh
FILES=*
for f in $(find $FILES); do 
v=`echo $f | sed -e '/\(.*\..*\)/ !d' | sed -e "s/^.*/${File} ${INST\_FILES} &/" | sed -e "s/\( \)\([a-zA-Z0-9]*\/\)/\//" | sed -e "s/\(\/\)\([a-zA-Z0-9\_\-\(\)\{\}$]*\.[a-zA-Z0-9]*\)/ /"`
sed -i.backup -e "s/\;Insert files here/$v\n&/" $nsisscript 
done 

Could you please help me understand what the difference is between the two cases and why I get this error ?

您能否帮助我理解这两种情况之间的区别以及为什么会出现此错误?

Thanks in advance!

提前致谢!

回答by neuro

Well my guess was that your escaping of underscore in INST_FILES is strange as underscore is not a special character in shell nor in sed. The error disappear when you delete the '\' before '_'

好吧,我的猜测是您在 INST_FILES 中转义下划线很奇怪,因为下划线在 shell 和 sed 中都不是特殊字符。当您删除 '_' 之前的 '\' 时,错误消失

my 2 cents

我的 2 美分

回答by Gordon Davisson

Parsing inside of backquote-style command substitution is a bit weird -- it requires an extra level of escaping (i.e. backslashes) to control when expansions take place. Ugly solution: add more backslashes. Better solution: use $()instead of backquotes -- it does the same thing, but without the weird parsing and escaping issues.

解析反引号样式的命令替换内部有点奇怪——它需要额外的转义级别(即反斜杠)来控制何时进行扩展。丑陋的解决方案:添加更多反斜杠。更好的解决方案:使用$()而不是反引号——它做同样的事情,但没有奇怪的解析和转义问题。

BTW, your script seems to have some other issues. First, I don't know about the sedon your system, but the versions I'm familiar with don't interpret \nin the substitution as a newline (which I presume you want), but as a literal ncharacter. One solution is to include a literal newline in the substitution (preceded by a backslash).

顺便说一句,您的脚本似乎还有其他一些问题。首先,我不知道sed您系统上的 ,但是我熟悉的版本\n在替换中不会将换行符解释为换行符(我认为您想要),而是将其解释为文字n字符。一种解决方案是在替换中包含一个文字换行符(前面有一个反斜杠)。

Also, the loop executes for each found file, but for files that don't have a period in the name, the first sedcommand removes them, $vis empty, and you add a blank line to myscript.sh. You should either put the filtering sedcall in the forstatement, or add it as a filter to the findcommand.

此外,循环会针对每个找到的文件执行,但对于名称中没有句点的文件,第一个sed命令将删除它们,该命令$v为空,然后您将一个空行添加到 myscript.sh。您应该将过滤sed调用放在for语句中,或者将其作为过滤器添加到find命令中。

#!/bin/bash
nsisscript=myscript.sh
nl=$'\n'
FILES=*
for f in $(find $FILES -name "*.*"); do 
    v=$(echo $f | sed -e "s/^.*/${File} ${INST\_FILES} &/" | sed -e "s/\( \)\([a-zA-Z0-9]*\/\)/\//" | sed -e "s/\(\/\)\([a-zA-Z0-9\_\-\(\)\{\}$]*\.[a-zA-Z0-9]*\)/ /")
    sed -i.backup -e "s/\;Insert files here/$v\$nl&/" $nsisscript 
done