shell 为什么handle_exit中的退出代码总是0,以及如何区分错误和成功?

h4cxqtbf  于 2023-08-07  发布在  Shell
关注(0)|答案(1)|浏览(117)

我有一个bash脚本,我想做一个pg_dumpall和上传到S3,然后发送一封电子邮件给管理员,如果出了问题,与确切的错误消息和另一封电子邮件的情况下,一切正常。

#!/usr/bin/env bash

set -e
set -E
set -o pipefail
set -u
set -x

IFS=$'\n\t'

log="/tmp/error.txt"
exec 2>"$log"

handle_error() {    
    error_message="$(< "$log")"
    echo "$(caller): ${BASH_COMMAND}: ${error_message}"
    exit 1
}

handle_exit() {
    rm -rf ${backup_dirname}
    rm /tmp/error.txt
    echo "We are exiting $?"
}

trap "handle_exit" EXIT
trap "handle_error $?" ERR

backup_root="$HOME/Desktop/backups"
backup_dirname="$( date '+%Y_%m_%d_%HH_%MM_%SS' )"
backup_path="${backup_root}/${backup_dirname}"
encoding="UTF8"
globals_filename="globals.dump"
host="localhost"
port="5432"
username="abc"

mkdir -p "${backup_path}"
cd "${backup_root}"

pg_dumpall \
    --no-role-passwords \
    --no-password \
    --globals-only \
    --encoding="${encoding}" \
    --file="${backup_dirname}/${globals_filename}" \
    --host="${host}" \
    --port="${port}" \
    --username="${username}"

字符串
在我上面的脚本中,当pg_dumpall由于任何原因失败时,它调用handle_error,然后在这里调用handle_exit。=零

  • 我可以从handle_error发送一封电子邮件来处理失败案例,但成功案例又如何呢?
  • handle_exit是用$?在两种情况下均为0
  • 另外,如果我的电子邮件发送代码在handle_error中生成错误,会发生什么?
  • 如何区分成功状态和错误状态?
  • 有没有更好的方法来获取错误消息,而不通过管道传输到/tmp/error. txt

这是运行出错时的输出

+ IFS='
        '
+ log=/tmp/error.txt
+ exec
50 ./scripts/test-local-backup.sh: pg_dumpall --no-role-passwords --no-password --globals-only --encoding="${encoding}" --file="${backup_dirname}/${globals_filename}" --host="${host}" --port="${port}" --username="${username}": + trap handle_exit EXIT
+ trap 'handle_error 0' ERR
+ backup_root=/Users/vr/Desktop/backups
++ date +%Y_%m_%d_%HH_%MM_%SS
+ backup_dirname=2023_07_28_15H_58M_12S
+ backup_path=/Users/vr/Desktop/backups/2023_07_28_15H_58M_12S
+ encoding=UTF8
+ globals_filename=globals.dump
+ host=localhost
+ port=5432
+ username=abc
+ mkdir -p /Users/vr/Desktop/backups/2023_07_28_15H_58M_12S
+ cd /Users/vr/Desktop/backups
+ pg_dumpall --no-role-passwords --no-password --globals-only --encoding=UTF8 --file=2023_07_28_15H_58M_12S/globals.dump --host=localhost --port=5432 --username=abc
pg_dumpall: error: connection to server at "localhost" (::1), port 5432 failed: FATAL:  role "abc" does not exist
++ handle_error 0
We are exiting 0


这就是一次成功的跑步

+ IFS='
        '
+ log=/tmp/error.txt
+ exec
We are exiting 0

wydwbb8l

wydwbb8l1#

handle_exit是用$?在两种情况下均为0
因为那是你设的陷阱代码。

trap "handle_error $?" ERR

字符串
它使用双引号,因此在使用上一个命令的退出代码设置ERR陷阱时(在本例中成功设置了退出陷阱),字符串将被计算,因此ERR陷阱代码为handle_error 0。您应该使用像https://www.shellcheck.net/这样的工具来识别此类错误。
有没有更好的方法来获取错误消息,而不通过管道传输到/tmp/error. txt
您不喜欢当前解决方案的哪些方面?我建议使用mktemp而不是硬编码文件,但除此之外,我有点喜欢它。
也代替了

error_message="$(< "$log")"
echo "$(caller): ${BASH_COMMAND}: ${error_message}"


你可以简单地

echo -n "$(caller): ${BASH_COMMAND}: "
cat "$log"


我可以从handle_error发送一封电子邮件来处理失败案例,但成功案例又如何呢?
为什么不直接在脚本末尾发送成功。或者在退出陷阱中发送成功和错误。
另外,如果我的电子邮件发送代码在handle_error中生成错误,会发生什么?
据我所知,错误陷阱是禁用的,而执行错误陷阱,但我还没有找到源。
你也可以使用command || true或者

{
   commands
   which
   might
   fail
} || true


或者简单地执行set +e
为了阐明如何在陷阱周围传递退出代码,这里有一个简化的示例:

#!/bin/bash

trap 'handle_exit $?' EXIT
trap 'handle_err $?' ERR

handle_exit() {
  printf 'handle_exit: $? = %s   $1 = %s\n' $? $1
  exit $1
}

handle_err() {
  printf 'handle_err: $? = %s   $1 = %s\n' $? $1
  exit $(($1 + 1))
}

set -e
false


它会打印出来

handle_err: $? = 1   $1 = 1
handle_exit: $? = 2   $1 = 2


并且总体退出状态也是2。

相关问题