Локальные переменные в bash: локальные против subshell - PullRequest
9 голосов
/ 07 января 2011

Насколько мне известно, есть два способа создания локальных переменных в функции 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).Но я могу себе представить, что создание подоболочки сопряжено с накладными расходами.

Так какой же подход лучше?Какие плюсы / минусы?

Ответы [ 2 ]

9 голосов
/ 07 января 2011

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

Если ваш сценарий будет интенсивно использоваться и производительность действительно имеет значение (так что у вас будетсотни пользователей запускают его одновременно, много раз в день), тогда вы можете беспокоиться о производительности суб-оболочки.OTOH, если вы запускаете его раз в месяц, а сценарий в целом выполняется менее чем за 10 секунд, вы, вероятно, этого не сделаете.

Однако, с точки зрения ясности, гораздо лучше быть явным и объявитьпеременные - это снижает риск взлома скрипта, потому что кто-то приходит и говорит, что «эта вложенная оболочка явно не нужна» (а на самом деле это не так; я бы хотел удалить вложенные оболочки из ваших функций).

Посмотрите на развитие сценариев Perl.Они начинались как общедоступные с переменными, появляющимися по требованию.Постепенно они стали более строгими, и теперь в обычном стиле предопределяются все переменные.В некоторой степени оболочки следуют по тому же пути - но не так строго, как Perl.Awk также интересный пример;его функции используют глобальные переменные, если они не являются аргументами для функции, что приводит к тому, что функции пишутся с 3 активными аргументами (скажем) и 5 ​​неактивными аргументами, которые эффективно определяют локальные переменные.Это немного эксцентрично, хотя и «работает».

0 голосов
/ 02 июня 2016

Теперь убедиться, что все функции всегда объявляют все переменные как локальные, довольно сложно.

Я думаю, что это очень подвержено ошибкам и предпочитаю всегда использовать 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"

Это приведет к выходу

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