我使用 shell 脚本来设置不同类型的虚拟机。这些脚本通常包含多行变量,需要使用sed
.
如果我像这样创建它们,一切都很好:
VAR="Config Line1\nConfig Line2\nConfig Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile
但这并不会使脚本变得非常可读,特别是因为文本块可能很长。
如果我这样写:
VAR="Config Line1
Config Line2
Config Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile
运行脚本时出现错误:sed: -e expression #1, char 31: unknown command:
C'`
有没有办法使用sed
这样声明的变量?
答案1
该命令的标准语法a
是:
sed -e 'a\
first line\
second line\
last line'
BSD(至少 FreeBSD 和 OS/X)sed
去掉前导空格, 和需要-e
解决一个错误。只要第一行非空,GNUsed
就允许将第一行移到右侧之后。a\
因此,您需要预处理输入:
VAR='content with
multiple lines
some with lead blanks
or even backslash\'
preprocessed_VAR=$(printf '%s\n' "$VAR" |
sed 's/\\/&&/g;s/^[[:blank:]]/\\&/;s/$/\\/')
sed -i -e "/MatchingPattern/a\\
${preprocessed_VAR%?}" somefile
(在 FreeBSD 或 OS/X 上替换-i
为-i ''
)。
在 GNU/Linux 上并使用 GNU shell ( bash
) 或zsh
,您可以执行以下操作:
sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"
这是可行的,因为bash
使用zsh
已删除的临时文件实现here-strings,并且Linux上的/dev/stdin被实现为文件的符号链接(这意味着它可以被打开多次,并且每次都在开始时打开)。
这里你也可以使用 GNUawk
来代替:
(export VAR
gawk -i /usr/share/awk/inplace.awk '{print}; /MatchingPattern/{print ENVIRON["VAR"]}' somefile)
不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
或者perl
(-i
来自哪里):
(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)
答案2
该错误是由于sed
附加命令a
在实际的后面需要一个反斜杠a
:
使用 GNU sed
:
$ sed "/pattern/a\\$VAR" file.in >file.out
据我所知, BSDsed
只能使用该命令将一行插入到文件中a
,除非换行符被正确转义。
关于如何使用 BSD 解决此问题的密切相关答案sed
:http://unix.stackexchange.com/a/60322