使用 bash 作为模板工具时如何在第一个错误时失败

使用 bash 作为模板工具时如何在第一个错误时失败

我正在寻找更好的版本set -e。那个更好的版本应该可以工作™。我简单地读过Bash常见问题解答/105并尝试过这种疯狂的做法,但我仍然不知道如何因错误而失败。

我的用例是我想从模板生成一个文本文件,如下所示:

#!/usr/bin/env bash

# none of these options helped to get the behavior I want: stop on first error
# set -euo pipefail
# shopt -s inherit_errexit
# set -o errexit
# trap ERR

cat <<< "
MYAPP_DATABASE_PASSWORD=$(pwgen -1 32)

MYAPP_USER_PASSWORD=$(pwgen -1 8)

MYAPP_CONFIGURATION_DATE=$(date --utc --iso-8601=ns)
"

或者,这种方法我也可以接受(其中template.txt包含一个文本文件这里的字符串从上面):

#!/usr/bin/env bash

# none of these options helped to get the behavior I want: stop on first error
# set -euo pipefail
# shopt -s inherit_errexit
# set -o errexit
# trap ERR

while read line; do
    [ -z "$line" ] || echo "# $line"
    cmd="echo $line"
    outline=$(eval $cmd)
    exitstatus=$?
    echo "$outline"
    echo "# exit status was $exitstatus"
done < "template.txt"

不幸的是,由于以下要求,上述两种方法都不适合我:我只是希望如果命令替换失败(例如由于pwgen未找到),整个事情就会崩溃。错误不应超过 1 个。

对于其他技术,所需的行为是默认的:

# this is an erb file                    
<%
require 'securerandom'
require 'date'
%>

MYAPP_DATABASE_PASSWORD=<%= SecureRandom.alphanumeric(32) %>

MYAPP_USER_PASSWORD=<%= SecureRandom.alphanumeric(8) %>

MYAPP_CONFIGURATION_DATE=<%= DateTime.now.new_offset.iso8601(6) %>

如果有拼写错误,SecureRandomerb立即退出并失败。

如何使用 bash 实现这种失败时崩溃的行为?

答案1

另一种选择是使用配置工具,例如安西布尔这允许你使用 jinja2模板,并且还允许您验证生成的文件,如果使用该文件的应用程序具有某种配置检查。

- name: Update sshd configuration safely, avoid locking yourself out
  template:
    src: etc/ssh/sshd_config.j2
    dest: /etc/ssh/sshd_config
    owner: root
    group: root
    mode: '0600'
    validate: /usr/sbin/sshd -t -f %s
    backup: yes

答案2

更多研究erb与 bash 模板相比,我更喜欢-like 解决方案。如果 bash 有一个快速失败的解决方案,那么它就太奇特了,没有用处(简单、清晰、可维护性……)。

我对简单的快速失败 bash 解决方案的所有尝试都被以下有关规则所否定bash 的简单命令扩展:

如果其中一个扩展包含命令替换,则该命令的退出状态是最后执行的命令替换的退出状态。

TL;DR:忘掉 bash 模板的想法吧,因为它太复杂了,没有什么用处。相反,选择专为该工作设计的高级工具。

相关内容