Выход из shell-скрипта в конце с ненулевым кодом в случае сбоя какой-либо команды - PullRequest
0 голосов
/ 06 июля 2018

Я делаю сценарий оболочки, который запускает несколько тестов как часть конвейера CI. Я хотел бы выполнить все тесты (Я НЕ ХОЧУ ВЫХОДИТЬ РАНЬШЕ, если один тест не пройден). Затем, в конце скрипта, я хотел бы вернуться с отрицательным кодом выхода, если какой-либо из тестов не прошел.

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

Моя текущая идея - создать флаг для отслеживания любых неудачных тестов:

flag=0
pytest -s || flag=1
go test -v ./... || flag=1
exit $flag

Это кажется странным и требует больше работы, чем необходимо, но я новичок в скриптах bash. Я что-то упустил?

Ответы [ 3 ]

0 голосов
/ 06 июля 2018

Единственный способ представить код less - это если бы в оболочке была какая-то специальная составная команда all, которая могла бы выглядеть примерно как

# hypothetical all command
all do
  pytest -s
  go test -v ./...
done

, чей статус выхода является логическим or статусов выхода содержащейся команды. (Аналогичная команда any будет иметь логический and статусов выхода своих команд в качестве своего собственного статуса выхода.)

Не имея такой команды, я бы использовал ваш нынешний подход. Вы можете адаптировать предложение @ melpomene к функции chk (которую я бы назвал после команды вместо того, чтобы вызывать вашу команду, чтобы она работала с произвольными командами оболочки):

chk () { flag=$(( flag | $? )); }

flag=0
pytest -s; chk
go test -v ./...; chk
exit "$flag"

Если вы не используете его ни для чего другого, вы можете использовать ловушку DEBUG для обновления flag перед каждой командой.

trap 'flag=$((flag | $?))' DEBUG
pytest -s
go test -v ./...
exit "$flag"

(Помните, что отладочная ловушка выполняется за до , когда оболочка выполняет другую команду, а не сразу после выполнения команды. Возможно, это имеет значение только в том случае, если вы ожидаете ловушка, срабатывающая между завершением последней команды и выходом из оболочки, но об этом все же стоит знать.)

0 голосов
/ 06 июля 2018

Я голосую за ответ Иниана. Ловушки кажутся идеальным способом.

Тем не менее, вы также можете оптимизировать вещи с помощью массивов.

#!/usr/bin/env bash

testlist=(
  "pytest -s"
  "go test -v ./..."
)

for this in "${testlist[@]}"; do
  $this || flag=1
done

exit $flag

Конечно, вы можете извлечь содержимое массива из другого файла, если хотите создать более общий тестовый набор, который может использоваться несколькими инструментами. Черт, mapfile может быть хорошим способом для заполнения массива.

0 голосов
/ 06 июля 2018

Один из возможных способов - перехватить ненулевой код выхода через trap с помощью ERR. Предполагая, что ваши тесты не содержат конвейеры | и просто возвращают код ошибки прямо в запущенную оболочку, вы можете сделать

#!/usr/bin/env bash

exitCodeArray=()

onFailure() {
    exitCodeArray+=( "$?" )
}

trap onFailure ERR

# Add all your tests here

addNumbers () {
    local IFS='+'
    printf "%s" "$(( $* ))"
}

Добавьте свои тесты в любом месте после приведенного выше фрагмента. Поэтому мы продолжаем добавлять код выхода в массив всякий раз, когда тест возвращает ненулевой код возврата. Таким образом, для окончательного утверждения мы проверяем, равна ли сумма элементов массива 0, потому что в идеальном случае все случаи должны возвращать это, если оно успешно. Мы сбрасываем trap, установленный до

trap '' ERR

if (( $(addNumbers "${exitCodeArray[@]}") )); then
    printf 'some of your tests failed\n' >&2
    exit -1
fi
...