Виконання exitв підпакеті є одним із недоліків:
#!/bin/bash
function calc { echo 42; exit 1; }
echo $(calc)
Сценарій роздруковує 42, виходить із допоміжної оболонки із кодом повернення 1та продовжує сценарій. Навіть заміна дзвінка на echo $(CALC) || exit 1не допомагає, оскільки код повернення echoдорівнює 0 незалежно від коду повернення calc. І calcвиконується до echo.
Ще більш дивовижним є завада ефекту exit, вкладаючи його у localвбудований, як у наступному сценарії. Я наткнувся на проблему, коли написав функцію перевірки вхідного значення. Приклад:
Я хочу створити файл з назвою "year month day.log", тобто 20141211.logна сьогодні. Дату вводить користувач, який може не надати розумного значення. Тому в своїй функції fnameя перевіряю повернене значення, dateщоб перевірити достовірність введення користувача:
#!/bin/bash
doit ()
{
local FNAME=$(fname "$1") || exit 1
touch "${FNAME}"
}
fname ()
{
date +"%Y%m%d.log" -d"$1" 2>/dev/null
if [ "$?" != 0 ] ; then
echo "fname reports \"Illegal Date\"" >&2
exit 1
fi
}
doit "$1"
Виглядає добре. Нехай сценарій буде названий s.sh. Якщо користувач викликає сценарій за допомогою ./s.sh "Thu Dec 11 20:45:49 CET 2014", файл 20141211.logстворюється. Якщо ж користувач вводить ./s.sh "Thu hec 11 20:45:49 CET 2014", сценарій виводить:
fname reports "Illegal Date"
touch: cannot touch ‘’: No such file or directory
У рядку fname…йдеться про те, що в підпакеті виявлено погані вхідні дані. Але exit 1кінець local …рядка ніколи не спрацьовує, оскільки localдиректива завжди повертається 0. Це тому local, що виконується після $(fname) і, таким чином, перезаписує свій код повернення. І через це сценарій продовжується і викликає touchпорожній параметр. Цей приклад простий, але поведінка bash може бути дуже заплутаною в реальному застосуванні. Я знаю, справжні програмісти не використовують місцевих жителів.☺
Щоб зрозуміти: без цього localсценарій скасовує, як очікувалося, коли вводиться недійсна дата.
Виправлення полягає в тому, щоб поділити лінію на зразок
local FNAME
FNAME=$(fname "$1") || exit 1
Дивна поведінка відповідає документації localв розділі manh на сторінці bash: "Стан повернення 0, якщо не використовується локальна поза функцією, недійсне ім'я або ім'я - змінна, що читається".
Хоча я не є клопотом, але я вважаю, що поведінка баш протикоректно. Я знаю послідовність виконання, все localж не слід маскувати порушене завдання.
Моя початкова відповідь містила деякі неточності. Після виявлення та поглибленої дискусії з mikeserv (дякую за це) я пішов їх виправити.