Bash sed在匹配单行字符串后追加多行字符串

Bash sed在匹配单行字符串后追加多行字符串,bash,sed,puppet,Bash,Sed,Puppet,如果可能的话,我想对这个解决方案使用sed。我的情况如下: 我有一个多行字符串,它将通过外部方式提供给sed——可能是puppetshellexec或bash脚本。字符串如下所示: $string = 'blah blah blah\nblahblah\nblah blah blah\n\n' 我想运行sed命令,在找到匹配项后追加此字符串- sed -i "/^\[org\/gnome\/login-screen\]/a banner-message-text='$string'" /etc

如果可能的话,我想对这个解决方案使用
sed
。我的情况如下:

我有一个多行字符串,它将通过外部方式提供给
sed
——可能是puppetshellexec或bash脚本。字符串如下所示:

$string = 'blah blah blah\nblahblah\nblah blah blah\n\n'
我想运行
sed
命令,在找到匹配项后追加此字符串-

sed -i "/^\[org\/gnome\/login-screen\]/a banner-message-text='$string'" /etc/dconf/db/gdm.d/00-mybanner
问题在于
sed
\n
字符解释为换行符。注意,我在那里认识到,我在
sed
命令中声明
$string
变量的方式可能会因执行方式不同而有所不同,但即使在命令行上手动键入字符串也会产生多行输出。因此,文件最终看起来像:

[org/gnome/login-screen]
banner-message-text='blah blah blah
blablah
blah blah blah

'
banner-message-enable=true
这会导致
dconf update
引发错误。我希望文件看起来像:

[org/gnome/login-screen]
banner-message-text='blah blah blah\nblablah\nblah blah blah\n\n'
banner-message-enable=true
但是我似乎无法让
sed
阻止自己解释
\n
。 谢谢

编辑-使用Puppet使用已实施的解决方案(@tom fenech)完成上下文:

  $banner_msg = 'blah blah blah\nblahblah\nblah blah blah\n\n'

  $comply_cmd = "find /etc/dconf/db/gdm.d -maxdepth 1 -type f -print0 | xargs -0 sed -i '/^banner-message-text=/d' || /bin/true && \
    (grep -q \"^\[org/gnome/login-screen\]\" /etc/dconf/db/gdm.d/99-banner && \
    sed -i \"/^\[org\/gnome\/login-screen\]/a banner-message-text='\$(printf '%q' \"${banner_msg}\")'\" /etc/dconf/db/gdm.d/99-banner) || \
    (echo -e \"\n\[org/gnome/login-screen]\" >> /etc/dconf/db/gdm.d/99-banner && \
    echo \"banner-message-text='${banner_msg}'\" >> /etc/dconf/db/gdm.d/99-banner)"

  $unless_cmd = "grep -q \"^banner-message-text='\$(printf '%q' \"${banner_msg}\")'$\" /etc/dconf/db/gdm.d/99-banner"

  exec { 'gdm-banner-msg':
    path     => '/sbin:/bin:/usr/sbin:/usr/bin',
    umask    => '022',
    provider => shell,
    command  => $comply_cmd,
    unless   => $unless_cmd,
    notify   => Exec['dconf-update'],
  }

谢谢大家!

你需要避开你的反斜杠:

$ string='blah blah blah\\nblahblah\\nblah blah blah\\n\\n'
$ echo $string
blah blah blah\\nblahblah\\nblah blah blah\\n\\n
$ cat foo.txt
foo
baz
test

$ sed -i "/^foo/a bar='$string'" foo.txt 
$ cat foo.txt 
foo
bar='blah blah blah\nblahblah\nblah blah blah\n\n'
baz
test

$

printf
%q
格式说明符一起使用。这为您解决了逃逸问题:

$ echo "$string"
blah blah blah\nblahblah\nblah blah blah\n\n
$ printf '%q' "$string"
blah\ blah\ blah\\nblahblah\\nblah\ blah\ blah\\n\\n
manbash

%q
使
printf
以一种格式输出相应的参数 可以作为shell输入重用

这意味着空格也是反斜杠转义的,但这并没有坏处

测试它:

$ cat file
[org/gnome/login-screen]
$ sed "/^\[org\/gnome\/login-screen\]/a banner-message-text='$(printf '%q' "$string")'" file
[org/gnome/login-screen]
banner-message-text='blah blah blah\nblahblah\nblah blah blah\n\n'

准备初始配置文件:

echo -e "[org/gnome/login-screen]\nbanner-message-enable=true"> /etc/dconf/db/gdm.d/00-mybanner
cat /etc/dconf/db/gdm.d/00-mybanner

[org/gnome/login-screen]
banner-message-enable=true
插入新的横幅消息而不解释\n字符:

string='blah blah blah\\nblahblah\\nblah blah blah\\n\\n'; sed -i "/^\[org\/gnome\/login-screen\]/a banner-message-text=\'$string\'" /etc/dconf/db/gdm.d/00-mybanner
见结果:

cat /etc/dconf/db/gdm.d/00-mybanner

[org/gnome/login-screen]
banner-message-text='blah blah blah\nblahblah\nblah blah blah\n\n'
banner-message-enable=true

要点是:在字符串中的每个\n前面加一个斜杠。这将阻止sed解释\n字符。

这三个答案都很有用,但我选择了@tom fenech,因为他的逻辑和命令顺序比post更复杂。使用他的策略,我可以使用正常的转义序列设置一个
$string
变量,并在需要运行
grep
sed
时使用
printf“%q”
,但是,当我需要运行
echo
echo-e
时,也可以使用原件。您刚刚说服我仔细查看
printf
的格式说明符。谢谢你的宝石!谢谢,我为此做了一些实验,在bash中设置字符串和在puppet中设置字符串的结果并不一致。我将在上面的问题中添加有关此主题的更多信息。