Обработка ошибок в Bash

220
задан 3 revs, 2 users 93%Noob 3 February 2017 в 18:12
поделиться

6 ответов

Используйте прерывание!

tempfiles=( )
cleanup() {
  rm -f "${tempfiles[@]}"
}
trap cleanup 0

error() {
  local parent_lineno="$1"
  local message="$2"
  local code="${3:-1}"
  if [[ -n "$message" ]] ; then
    echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}"
  else
    echo "Error on or near line ${parent_lineno}; exiting with status ${code}"
  fi
  exit "${code}"
}
trap 'error ${LINENO}' ERR

... тогда, каждый раз, когда Вы создаете временный файл:

temp_foo="$(mktemp -t foobar.XXXXXX)"
tempfiles+=( "$temp_foo" )

и $temp_foo будет удален на выходе, и текущий номер строки будет распечатан. (set -e аналогично даст Вам поведение выхода на ошибке, , хотя оно идет с серьезными протестами и ослабляет предсказуемость и мобильность кода).

можно или позволить вызову прерывания error для Вас (в этом случае, он использует код выхода по умолчанию 1 и никакое сообщение), или назовите его сами и обеспечьте явные значения; например:

error ${LINENO} "the foobar failed" 2

выйдет с состоянием 2 и даст явное сообщение.

150
ответ дан Charles Duffy 23 November 2019 в 04:07
поделиться

Я использовал

die() {
        echo $1
        kill $
}

прежде; я думаю, потому что 'выход' перестал работать для меня по некоторым причинам. Вышеупомянутые значения по умолчанию походят на хорошую идею, все же.

3
ответ дан pjz 23 November 2019 в 04:07
поделиться

Это - прекрасное решение. Я просто хотел добавить

set -e

как элементарный ошибочный механизм. Это сразу остановит Ваш сценарий, если простая команда перестанет работать. Я думаю, что это должно было быть поведением по умолчанию: так как такие ошибки почти всегда показывают что-то неожиданное, это не 'действительно нормально', чтобы продолжать выполнять следующие команды.

115
ответ дан Bruno De Fraine 23 November 2019 в 04:07
поделиться

Другое соображение является кодом выхода для возврата. Просто" 1" является довольно стандартным, хотя существует горстка зарезервированные коды выхода, которые колотят себя использование , и та же самая страница утверждает, что пользовательские коды должны быть в диапазоне 64-113 для приспосабливания стандартам C/C++.

Вы могли бы также рассмотреть подход битовый вектора что mount использование для его кодов выхода:

 0  success
 1  incorrect invocation or permissions
 2  system error (out of memory, cannot fork, no more loop devices)
 4  internal mount bug or missing nfs support in mount
 8  user interrupt
16  problems writing or locking /etc/mtab
32  mount failure
64  some mount succeeded

OR - луг коды вместе позволяет Вашему сценарию сигнализировать о нескольких одновременных ошибках.

6
ответ дан yukondude 23 November 2019 в 04:07
поделиться

Я предпочитаю звонить по очень легкому телефону. Так что я использую что-то, что кажется немного сложным, но простым в использовании. Обычно я просто копирую и вставляю приведенный ниже код в свои скрипты. За кодом следует пояснение.

#This function is used to cleanly exit any script. It does this displaying a
# given error message, and exiting with an error code.
function error_exit {
    echo
    echo "$@"
    exit 1
}
#Trap the killer signals so that we can exit with a good message.
trap "error_exit 'Received signal SIGHUP'" SIGHUP
trap "error_exit 'Received signal SIGINT'" SIGINT
trap "error_exit 'Received signal SIGTERM'" SIGTERM

#Alias the function so that it will print a message with the following format:
#prog-name(@line#): message
#We have to explicitly allow aliases, we do this because they make calling the
#function much easier (see example).
shopt -s expand_aliases
alias die='error_exit "Error ${0}(@`echo $(( $LINENO - 1 ))`):"'

Я обычно помещаю вызов функции очистки вместе с функцией error_exit, но это варьируется от сценария к сценарию, поэтому я оставил это. Ловушки улавливают общие завершающие сигналы и следят за тем, чтобы все было очищено. Псевдоним - вот что делает настоящую магию. Люблю все проверять на отказ. В общем, я называю программы "если!" заявление типа. Вычитая 1 из номера строки, псевдоним скажет мне, где произошел сбой. К тому же это очень просто вызвать, и это в значительной степени доказательство идиота. Ниже приведен пример (просто замените / bin / false на то, что вы собираетесь вызвать).

#This is an example useage, it will print out
#Error prog-name (@1): Who knew false is false.
if ! /bin/false ; then
    die "Who knew false is false."
fi
11
ответ дан 23 November 2019 в 04:07
поделиться

Эквивалентная альтернатива "set -e" -

set -o errexit

Это делает значение флага несколько понятнее, чем просто "-e".

Случайное добавление: для временного отключения флага , и вернуться к значению по умолчанию (продолжение выполнения независимо от кодов выхода), просто используйте

set +e
echo "commands run here returning non-zero exit codes will not cause the entire script to fail"
echo "false returns 1 as an exit code"
false
set -e

. Это исключает надлежащую обработку ошибок, упомянутую в других ответах, но выполняется быстро и эффективно (как и bash).

22
ответ дан 23 November 2019 в 04:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: