我需要在heredoc中嵌入shell脚本的片段,作为创建cloud-init脚本的一部分,以配置Ubuntu 14.04 LTE机器。演示该问题的脚本的简化版本如下:
#!/bin/bash
cloudconfig=$(cat <<EOF
if host \$NAMESERVER 1>/dev/null 2>&1; then
case \$reason in
BOUND|RENEW|REBIND|REBOOT) nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
server \$NAMESERVER
update delete \$HOST_NAME A
update add \$HOST_NAME \$TTL A \$HOST_ADDR
send
EOX
;;
esac
fi
EOF
)
echo "${cloudconfig}"
运行上述脚本失败如下:
Little-Net:orchestration minfrin$ bash /tmp/test.sh
could not read key from /var/lib/dhcp/nsupdate.{private,key}: file not found
couldn't get address for '$NAMESERVER': not found
有问题的角色是“REBOOT”右侧的右括号,显而易见的解决办法是逃避角色:
BOUND|RENEW|REBIND|REBOOT\) nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
然后,这个反斜杠字符最终会出现在最终的cloudconfig变量中,而该变量又会破坏输出:
Little-Net:orchestration minfrin$ bash /tmp/test.sh
if host $NAMESERVER 1>/dev/null 2>&1; then
case $reason in
BOUND|RENEW|REBIND|REBOOT\) nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
server $NAMESERVER
update delete $HOST_NAME A
update add $HOST_NAME $TTL A $HOST_ADDR
send
EOX
;;
esac
fi
上面的这个特定片段是正在编写的依赖于变量插值的较大文件的一部分,因此在那里引用带有&gt;&gt;“EOF”的heredoc会破坏我们脚本的其余部分。
如果没有通过heredoc泄漏转义字符,我如何逃避“)”字符?
答案 0 :(得分:2)
由于这似乎是一个bash 3.x解析问题(因为它可以在bash 4.x中工作,因为可以看到here),你需要避免解析器混淆。这似乎对我有用:
#!/bin/bash
rp=")"
cloudconfig=$(cat <<EOF
if host \$NAMESERVER 1>/dev/null 2>&1; then
case \$reason in
BOUND|RENEW|REBIND|REBOOT${rp} nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
server \$NAMESERVER
update delete \$HOST_NAME A
update add \$HOST_NAME \$TTL A \$HOST_ADDR
send
EOX
;;
esac
fi
EOF
)
echo "${cloudconfig}"
答案 1 :(得分:1)
由于你没有任何参数,你实际上想在这里的文档中扩展,我只会引用整个事情(这可以为你节省大量的显式反斜杠):
#!/bin/bash
cloudconfig=$(cat <<'EOF'
if host $NAMESERVER 1>/dev/null 2>&1; then
case $reason in
BOUND|RENEW|REBIND|REBOOT) nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
server $NAMESERVER
update delete $HOST_NAME A
update add $HOST_NAME $TTL A $HOST_ADDR
send
EOX
;;
esac
fi
EOF
)
echo "${cloudconfig}"
请注意,您也不能缩进EOX
,否则当您使用它时,此处的文档将无法正确终止。
#!/bin/bash
cloudconfig='
if host $NAMESERVER 1>/dev/null 2>&1; then
case $reason in
BOUND|RENEW|REBIND|REBOOT) nsupdate -k /var/lib/dhcp/nsupdate.key << EOX
server $NAMESERVER
update delete $HOST_NAME A
update add $HOST_NAME $TTL A $HOST_ADDR
send
EOX
;;
esac
fi'
echo "${cloudconfig}"
如果您需要允许某些参数扩展,您仍然可以使用多行字符串进行一些修改。无论何时需要插值,请关闭单引号并立即打开双引号。扩展完成后,关闭双重并重新打开单个。
cloudconfig='
if [[ $SOMEVARIABLE =='"$value"' ]]; then
...
'
答案 2 :(得分:0)
我通过在HEREDOC
内手动转义括号来解决此问题,然后在其后加上sed
语句以删除反斜杠。
long_string=$(cat << 'HEREDOC'
This is a string with \( escaped \) parenthesis.
HEREDOC
)
long_string=$(echo $long_string | sed -e 's:\\(:(:g' -e 's:\\):):g')
使用bash 4+会更好,但是随后我必须让团队中的所有人都使用mac's才能获得bash 4 +。