LINUX.ORG.RU

Возврат значения функции и последующая обработка значения

 , ,


0

1

Всем доброго времени суток.

Подскажите, почему такая штука. Допустим, есть функция и из неё я возвращаю 0 или 1. Но, if и test по разному обрабатывают return.

Допустим:

$ function test () { return 1; }
$ [[ test ]] && echo ok || echo not ok
ok
$ if test; then echo ok; else echo not ok; fi
not ok

Команда test обрабатывает успешность выполнения функции или как это работает? Как можно еще обработать return?

Ответ на: комментарий от AS

Такое же поведение. Дал вообще другие название:

$ function check_status () { return 1; }
$ [[ check_status ]] && echo ok || echo not ok
ok
$ if check_status; then echo ok; else echo not ok; fi
not ok
hanharr ()
Ответ на: комментарий от hanharr

А что смущает?

check_status возвращает 1, что bash'ем понимается как false; echo ok возвращает 0, то есть true.

false && true || echo not ok

Deleted ()
Ответ на: комментарий от Deleted

Меня смущает вопрос могу ли я использовать конструкцию check_status && echo ok || echo not ok вместо if check_status; then echo ok; else echo not ok; fi. Насколько они равнозначны?

hanharr ()
Ответ на: комментарий от hanharr

В этом контексте они логически эквивалентны, поскольку echo всегда вернет true. В случаях, вроде

if check_status
then
    foo
else
    bar
fi

- всё зависит от значений, которые вернут foo и bar. Надежней писать полную конструкцию.

Deleted ()
Ответ на: комментарий от Deleted

Я хочу использовать вот как:

function check_slave_status () {
    local slave_io_running
    local slave_sql_running
    local retval

    slave_io_running=$(/usr/bin/mysql -uroot -e "SHOW SLAVE STATUS\G" | grep "Slave_IO_Running:" | awk '{print $2}')
    slave_sql_running=$(/usr/bin/mysql -uroot -e "SHOW SLAVE STATUS\G" | grep "Slave_SQL_Running:" | awk '{print $2}')

    if [[ "$slave_io_running" == "Yes" && "$slave_sql_running" == "Yes" ]]; then
        retval=0
    else
        retval=1
    fi

    return $retval
}

function restart_replication () {
    local stop_slave
    local start_slave
    local last_errno
    local errno
    local retval

    stop_slave=$(/usr/bin/mysql -uroot -e "stop slave;")
    start_slave=$(/usr/bin/mysql -uroot -e "start slave;")
    last_errno=$(/usr/bin/mysql -uroot -e "SHOW SLAVE STATUS\G" | grep "Last_Errno:" | awk '{print $2}')
    errno=1032

    if [[ $last_errno = "$errno" ]]; then
        $stop_slave
        $start_slave
        check_slave_status && retval=0 || retval=1
    else
        retval=1
    fi

    return $retval
}

Т.е. я хочу обратиться из функции, которая перезапустила репликацию к функции, которая проверяет её статус и вернуть результат перезапуска.

hanharr ()
Ответ на: комментарий от hanharr

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

Deleted ()
Ответ на: комментарий от Deleted

Я решил вынести, потому что эта проверка используется больше, чем в одном месте. Но, возможно вы правы.

hanharr ()
Ответ на: комментарий от hanharr
$ function check_status () { return 1; }
$ [[ check_status ]] && echo ok || echo not ok
ok
$ if check_status; then echo ok; else echo not ok; fi
not ok

Когда вы используете конструкцию «if <команда>», то bash выполняет команду (или функцию) и анализирует её код возврата.

Когда вы используете конструкцию if [[ check_status ]] ... или if [ check_status ] ..., то bash воспринимает эту конструкцию как сокращение для:

if test -n check_status ...

или, что аналогично:

if [[ -n check_status ]] ...

:))))

Для наглядности попробуйте добавить в вашу функцию какое-нибудь echo и вы увидите, что в первом варианте ваша функция вообще не вызывается. Ну или просто включите режим отладки «set -x».

vinvlad ()

return 1

1 - это статус ошибки в shell.

Статус успеха - 0.

[[ test ]]

А здесь, как выше уже написали, test вообще не вызывается, поскольку выступает обычным тестовым аргументом для команды [[.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)

... Как можно еще обработать return?

В bash есть специальная переменная $?, которой после выполнения любой команды/функции присваивается соответствующий код возврата. Только с этой переменной нужно обходиться аккуратно - предварительно, сразу после выполнения команды, её нужно сохранять в какой-нибудь локальной переменной, чтобы не запортить следующими командами, а потом уже проверять значение.
Типа:

check_status
rc="$?"
...
if [ "$rc" = "0" ]; then
...
fi

P.S. Работая с bash рекомендую всегда иметь под рукой Advanced Bash−Scripting Guide.

vinvlad ()
Ответ на: комментарий от vinvlad

Про $? я знаю, в данном случае избыточна. За справочник спасибо.

hanharr ()

Лучше бери хоть brainfuck вместо баша, меньше будешь вот так спотыкаться.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.