在 bash v3 heredoc 中转义右括号字符
Escaping the close-bracket character in a bash v3 heredoc
我需要在 heredoc 中嵌入 shell 脚本的片段,作为创建云初始化脚本的一部分,以提供 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
上面的这个特定片段是正在编写的一个更大的文件的一部分,该文件依赖于变量插值,因此在此处引用 >>"EOF" 将破坏我们脚本的其余部分。
如何在不通过 heredoc 泄漏转义字符的情况下转义“)”字符?
因为这似乎是一个 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}"
由于您没有任何实际想要在此处文档中扩展的参数,因此我将只引用整个内容(这样可以为您节省大量明确的反斜杠):
#!/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
...
'
我通过在 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 来获得 bash 4+。
我需要在 heredoc 中嵌入 shell 脚本的片段,作为创建云初始化脚本的一部分,以提供 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
上面的这个特定片段是正在编写的一个更大的文件的一部分,该文件依赖于变量插值,因此在此处引用 >>"EOF" 将破坏我们脚本的其余部分。
如何在不通过 heredoc 泄漏转义字符的情况下转义“)”字符?
因为这似乎是一个 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}"
由于您没有任何实际想要在此处文档中扩展的参数,因此我将只引用整个内容(这样可以为您节省大量明确的反斜杠):
#!/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
...
'
我通过在 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 来获得 bash 4+。