Bash 脚本:捕获语句块中的错误

Bash 脚本:捕获语句块中的错误

我有一个大型 iptables 规则集,我用自己的 bash 脚本来管理它。脚本中的大多数命令都是简单的单语句 iptables 命令。我试图通过在脚本执行时添加成功/失败输出来改进脚本。

我将脚本分成了不同的部分。一个例子是 FORWARD 链部分,其中所有规则都应用于 FORWARD 链。在该部分的开头,我输出脚本已开始应用 FORWARD 规则,最后,我想输出所有规则是否都已成功应用,或者是否有任何规则不起作用。基本思路如下:

#Start FORWARD section
echo -ne "Applying FORWARD rules..."

#rule 1
/sbin/iptables -A FOWRARD...

#rule 2
/sbin/iptables -A FORWARD...

echo -ne "\t\t\t[OK]\n"

我想要做的是捕获每个 iptables 命令可能导致的任何输出或错误,并将它们存储在数组或其他东西中。然后在块的末尾,使用 if 语句评估数组以查看是否存在任何错误。如果没有,则输出 [OK] 状态,如果有,则输出 [FAILED] 状态并显示相关错误。

有没有办法可以对整个规则块执行此操作,而无需将每个 iptables 规则包装在 if [ $? != 0 ] 表达式中?

答案1

您可以使用trapshell 内置命令,当命令的退出状态为非零时,会调用处理函数。您可以将必要的信息(如行号和退出状态)传递给错误处理函数。

例子:

#!/bin/bash

handle_error() {
    echo "FAILED: line $1, exit code $2"
    exit 1
}

trap 'handle_error $LINENO $?' ERR 

# your commands here
# ...

echo "OK"

答案2

下面的脚本将定义recordfailure应添加到命令前面的函数,如函数定义后的示例所示。如果命令返回非零,则记录标准错误流。最后,检查错误日志并[OK]相应[FAIL]地打印。

#!/bin/bash

# Redirect file descriptor #3 to standard output (used in recordfailure)
exec 3>&1

# create an array for holding failures
declare -a failures

# recordfailure command arg1 arg2 ... argN
recordfailure() {
    local error retval
    # Run the command and store error messages (output to the standard error
    # stream in $error, but send regular output to file descriptor 3 which
    # redirects to standard output
    error="$("$@" 2>&1 >&3)"
    retval=$?
    # if the command failed (returned a non-zero exit code)
    if [ $retval -gt 0 ]; then
        if [ -z "$error" ]; then
            # create an error message if there was none
            error="Command failed with exit code $retval"
        fi
        # uncomment if you want the command in the error message
        #error="Command $* failed: $error"

        # append the error to $failures, ${#failures[@]} is the length of
        # the array and since array start at index 0, a new item is created
        failures[${#failures[@]}]="$error"
        # uncomment if you want to show the error immediately
        #echo "$error"
    fi
}
recordfailure iptables -A FORWARD ...
recordfailure iptables -A FORWARD ...
# if the length of the failures array equals 0 (no items) everything is OK
if [ ${#failures[@]} -eq 0 ]; then
    echo "[OK]"
else
    echo "[FAIL]"
    # list every error
    for failure in "${failures[@]}"; do
        # optionally color it, format it or whatever you want to do with it
        echo "error: $failure"
    done
fi

如果您不想显示标准输出,请删除exec 3>&1并替换>&3>/dev/null

答案3

你是指这样的事情吗?

ok=1

#Start FORWARD section
echo -ne "Applying FORWARD rules..."

#rule 1
/sbin/iptables -A FOWRARD... || ok=0

#rule 2 
/sbin/iptables -A FORWARD... || ok=0

echo -ne "\t\t\t"
if [ $ok -eq 1 ]; then
  echo "[OK]"
else
  echo "[fail]"
fi

相关内容