Vagrant Provisioner中sed命令报unterminated `s' command问题排查
这问题我实操时碰到过!核心症结是Vagrant的here-doc解析逻辑和普通shell不一样,它会把你写的\n当成纯字面字符处理,而不是转义成实际换行符,直接导致sed的替换表达式结构断裂,触发unterminated 's' command错误。
先搞懂背后的逻辑差异
普通shell下为什么正常?
在常规bash环境中,双引号包裹的字符串里,\n会被shell自动解析为实际换行符。sed接收到的替换内容是真正的两行文本,完全符合s命令的格式要求,所以能顺利执行。Vagrant here-doc里为啥失效?
Vagrant的provision脚本如果用<<-EOF这类here-doc,默认不会解析字符串中的转义字符——它会原封不动把\n作为普通字符串传给虚拟机内的shell。此时sed拿到的替换内容是security:\n authorization: enabled(带反斜杠的n),而非预期的换行结构。sed会把\当成未完成的转义标记,认为你的s命令还没写完,自然就报错了。
几种可行的解决方案
方案1:直接用实际换行代替\n
把换行符直接打出来,保持MongoDB配置要求的缩进:
sudo sed -i "s/#security:/security: authorization: enabled/g" /etc/mongod.conf
如果用<<-EOF格式的here-doc,换行后的行可以用tab缩进(别用空格,避免破坏MongoDB的配置格式),示例Vagrant配置片段:
Vagrant.configure("2") do |config| config.vm.provision "shell", inline: <<-SHELL sudo sed -i "s/#security:/security: authorization: enabled/g" /etc/mongod.conf SHELL end
方案2:用bash的ANSI-C转义解析\n
用$'...'包裹sed命令,让虚拟机内的bash主动解析转义字符:
sudo sed -i $'s/#security:/security:\\n authorization: enabled/g' /etc/mongod.conf
$'...'是bash的特性,会把内部的\n转成实际换行符,Vagrant会把整个结构作为整体传递,sed最终能拿到正确的两行替换内容。
方案3:用printf生成带换行的替换内容
借助printf输出标准的换行文本,避免转义冲突:
sudo sed -i "s/#security:/$(printf 'security:\n authorization: enabled')/g" /etc/mongod.conf
printf会直接输出带换行的字符串,替换到sed命令后,sed接收到的就是符合要求的配置格式。
内容的提问来源于stack exchange,提问作者Single Entity

