Правильный способ заказа функций и условий - PullRequest
3 голосов
/ 10 апреля 2019

Я пишу сценарий bash для настройки сервера NFS. Мне удалось настроить сервер NFS вручную, и он полностью функционален. Теперь я хочу воспроизвести те же шаги в скрипте bash. У меня есть все шаги и каждый шаг, команда оболочки, я помещаю в функцию bash. Затем у меня есть основной раздел, где я делаю вызовы функций, всего 16 функций. В основном разделе я хочу проверить возвращаемое значение функции, обычно это просто «$?» значение

if [ "function_1" -eq "0" ]; then
    echo "Success"
else
    echo "Failure"
fi

Поскольку имеется 16 вызовов функций, где каждый вызов функции зависит от успешности предыдущей функции, все становится немного нехорошо

if [ "function_1" -eq "0" ]; then
    if [ "function_2" -eq "0" ]; then
        if [ "function_3" -eq "0" ]; then
            if [ "function_..." -eq "0" ]; then
                if [ "function_16" -eq "0" ]; then

У меня вопрос: это правильный способ структурировать программу или лучше вообще не использовать функции, а просто выполнить проверку команд в главном разделе

chmod -R 0755 $SHARED_FILE_SYSTEM
if [ "$?" -eq "0" ]; then
    echo "Success"
else
    echo "Failure
fi

Ответы [ 3 ]

1 голос
/ 11 апреля 2019

Если функции принимают аргументы (а разные функции принимают разные аргументы), один из способов упростить проверку команд - использовать для этого функцию:

#! /bin/bash -p

# ...

# Run a configuration command (passed as arguments) and report if it succeeds or
# fails.  Call 'exit' if the command fails.
function doconf
{
    if "$@" ; then
        printf 'Success: %s\n' "$*"
        return 0
    else
        local status=$?
        printf 'Failure: %s (%d)\n' "$*" "$status"
        exit "$status"
    fi
}

doconf function_1 arg1
doconf function_2 arg2a arg2b
# ...
doconf function_15 arg15a arg15b arg15c arg15d
doconf function_16 arg16a arg16b arg16c

Если вы не хотите, чтобы программа немедленно закрывалась при сбое функции, вы можете перехватить exit, выполненный doconf, поместив вызовы doconf в подоболочку:

# ...

(
    doconf function_1 arg1
    doconf function_2 arg2a arg2b
    # ...
    doconf function_15 arg15a arg15b arg15c arg15d
    doconf function_16 arg16a arg16b arg16c
)

# Program execution continues here, even if a `doconf` exits
# ...
  • doconf не великое имя. Вы можете изменить его.
  • doconf должен иметь проверку, чтобы убедиться, что указан хотя бы один аргумент (имя команды).
1 голос
/ 11 апреля 2019

Это анти-шаблон для проверки $?. Лучше просто проверить команду непосредственно в операторе if:

if cmd; then
    ...
fi

Наличие явных if проверок и сообщений об ошибках громоздко. Обычный шаблон, позволяющий избежать этого, - просто выйти из программы в случае сбоя и положиться на нее, чтобы напечатать собственное сообщение об ошибке. Вам не нужно ничего печатать самостоятельно. Затем вы можете использовать || return или || exit для спасения при сбое команды, где a || b является сокращением для if ! a; then b; fi.

function_1 || exit
function_2 || exit
function_3 || exit
...

Обратите внимание, что return и exit будут автоматически использовать $?.

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

set -e

function_1
function_2
function_3
...
1 голос
/ 10 апреля 2019

Один из вариантов - составить список функций и запустить их в цикле, как показывает этот Shellcheck -чистый код:

#! /bin/bash -p

# ...

config_functions=(
    function_1
    function_2
    # ...
    function_15
    function_16 )

for cfunc in "${config_functions[@]}" ; do
    if "$cfunc" ; then
        printf 'Success: %s\n' "$cfunc"
    else
        printf 'Failure: %s (%d)\n' "$cfunc" "$?"
    fi
done
  • Нет необходимости явно проверять $?, и Shellcheck выдаст предупреждение, если вы это сделаете. См. Shellcheck SC2181 .
  • Если вы хотите немедленно прекратить работу в случае сбоя какой-либо функции, введите break или exit "$?", в зависимости от ситуации, в ветку 'Failure' if.

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

Рассмотрите возможность использования инструмента управления конфигурацией, такого как Chef , Puppet , Ansible или Salt для настройки службы NFS. Они имеют много преимуществ перед скриптами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...