Локальные переменные в bash: local vs subshell
насколько я знаю, есть два способа создать локальные переменные в функции bash: создать подрешетку или объявить каждую переменную как локальную.
например:
# using local
function foo
{
local count
for count in $(seq 10)
do
echo $count
done
}
или
# using subshell
function foo
{
(
for count in $(seq 10)
do
echo $count
done
)
}
очевидно, что версия, использующая подрешетку, проще писать, потому что вам не нужно заботиться о объявлении всех переменных локальными (не говоря уже о переменных среды), созданных/экспортированных такими инструментами, как команде getopts). Но я могу представить, что создание у subshell есть накладные расходы.
Так какой же подход лучше? Каковы плюсы и минусы?
2 ответов
создание под-оболочки включает в себя fork()
, поэтому он определенно имеет накладные расходы по сравнению с локальной переменной. Хотя суб-оболочки дешевы - вы не беспокоитесь о их стоимости, когда вам это нужно, - они не бесплатны.
Если ваш скрипт будет активно использоваться, и производительность действительно имеет значение (так что у вас будут сотни пользователей, которые будут запускать его одновременно, много раз в день), тогда вы можете беспокоиться о стоимости производительности суб-оболочки. OTOH, если вы запускаете его раз в месяц и сценарий в целом работает менее 10 секунд, вы, вероятно, не будет.
однако, с точки зрения ясности, гораздо лучше быть явным и объявлять переменные - это уменьшает риск взлома скрипта, потому что кто-то приходит и говорит: "Эта под-оболочка явно не нужна" (и это действительно не так; я хотел бы удалить под-оболочки из ваших функций).
посмотрите на эволюцию скриптов Perl. Они начали как free-for-all с переменными, входящими в существование по требованию. Они постепенно стали более строгими,с нормальным стилем, который теперь должен предшествовать всем переменным. В какой - то степени снаряды следовали аналогичному пути, но не так строго, как Perl. Awk также является интересным примером; его функции используют глобальные переменные, если они не являются аргументами функции, что приводит к написанию функций с 3 активными аргументами (скажем) и 5 неактивными аргументами, которые эффективно определяют локальные переменные. Это немного эксцентрично, хотя это "работает".
Теперь, убедившись, что все функции всегда объявляют все переменные как локальные, довольно сложно.
Я думаю, что это очень подвержено ошибкам и предпочитает всегда использовать функции subshell:
f() (
echo "we are a subshell"
)
не нужно объявлять локальные переменные, но и нет способа изменить глобальные переменные. Что, на мой взгляд, хорошо!
одним из дополнительных последствий является то, что вам всегда нужно проверять код возврата / выхода таких функций и действовать соответственно! Это потому, что ты не удается выйти из скрипта из функции subshell!
f() (
echo "Trying to exit"
exit 1
)
f
echo "Did not exit"
Это не выйдет из вашего сценария. Вам нужно сделать это так:
f() (
echo "Trying to exit"
exit 1
)
f || exit $?
echo "Did not exit"
это выйдет