为什么 sed 给我一个关于未终止的“s”的错误?

为什么 sed 给我一个关于未终止的“s”的错误?

我在 bash 脚本中有一组 sed 替换,并且收到有关未终止的“s”命令的错误。 sed 行如下所示:

sed -n -e "s/TMPFOO1/$FOO1/" -e "s/TMPFOO2/$FOO2/" -e "s/TMPFOO3/$FOO3/" -e "s/TMPFOO4/$FOO4/" -e "s/TMPFOO5/$FOO5/" /home/foo/template > /home/foo/template/finishedresult

但出于某种原因,bash 不喜欢这个,我收到一个错误

sed: -e expression #4, char 69: unterminated `s' command

我在这里缺少什么?如何让 SED 输入变量?在我看来他们都被终止了。

答案1

您无法在 sed 命令中安全地插入变量,因为替换是由 shell 执行的,而不是由 sed 执行的。变量的值成为 sed 语法。例如,在 中"s/TMPFOO1/$FOO1/",如果$FOO1包含换行符,这将导致类似于您观察到的语法错误。如果$FOO1包含 a /,则这将终止s命令并可能导致错误或可能导致执行其他命令(如果后面的内容/恰好是有效的 sed 语法)。

虽然您可以执行第一遍替换以FOO1引用其特殊字符以包含在该 sed 命令中,但使用 awk 要简单得多。 awk 有变量的概念,以及用于设置变量初始值的命令行语法。

awk -v FOO1="$FOO1" -v FOO2="$FOO2" -v FOO3="$FOO3" -v FOO4="$FOO4" -v FOO5="$FOO5" '{
    sub(/TMPFOO1/, FOO1);
    sub(/TMPFOO2/, FOO2);
    sub(/TMPFOO3/, FOO3);
    sub(/TMPFOO4/, FOO4);
    sub(/TMPFOO5/, FOO5);
    print;
}' /home/foo/template > /home/foo/template/finishedresult

答案2

您的变量之一很可能$FOO包含由 解释的特殊字符sed

我有另一个版本,sed它会生成其他错误消息,但这里是类似问题的示例:

$ VAR=a
$ echo i | sed -e "s/i/"$VAR"/"
a
$ tmp> VAR=/
$ echo i | sed -e "s/i/"$VAR"/"
sed: 1: "s/i///
": bad flag in substitute command: '/'

在这种情况下,$VAR包含一个被解释为sed尾部斜杠的字符。

答案3

正如其他人在这里提到的,这取决于 FOO* 变量的内容。在您的情况下,使用sed是错误的选择,因为它可能包含一些特殊字符。

看一眼这个链接并查看函数gsub_literal

由于gsub_literal从 stdin 读取并写入 stdout,用法将是:

gsub_literal "$search" "$replace" < /home/foo/template > /home/foo/template/finishedresult

示例输出:

rany$ cat > foo.txt
a'
a'

rany$ gsub_literal a\' b < foo.txt 
b
b

答案4

通过在命令中尝试添加反斜杠,该问题已为我解决sed 's/.../.../g'。这个命令

sed 's/\"a/ä/g' input_file

给了我这个错误消息

sed:-e 表达式 #1,字符 9:未终止的“s”命令

当它作为 c-shell 脚本的一部分执行时,它仅对最新版本的 执行此操作sed,而不是对旧版本执行此操作。 (奇怪的是,当在命令行(在 tc-shell 中)给出相同的命令时,它可以正常工作)。

c-shell 脚本的问题已通过在字符前添加ä反斜杠来解决:

sed 's/\"a/\ä/g' input_file

相关内容