Что такое «объявить» в Bash?

Использование вашего кода:

nohup bash <<EOF &
WB=$1
sleep 2h;
commands...
kill \$WB
EOF

Обратите внимание, что $ 1 будет расширяться при чтении кода; чтобы $ WB расширялся при выполнении кода, необходимо заключить $ в кавычки.

8
06.05.2019, 07:24
2 ответа

В большинстве случаев достаточно неявного объявления вbash

asdf="some text"

Но иногда вы хотите, чтобы значение переменной было только целым числом (, поэтому, если оно впоследствии изменится, даже автоматически, оно может быть изменено только на целое число, в некоторых случаях по умолчанию равно нулю )и может использовать:

declare -i num

или

declare -i num=15

Иногда вам нужны массивы, и тогда вам нужноdeclare

declare -a asdf   # indexed type

или

declare -A asdf   # associative type

Вы можете найти хорошие руководства по массивам в bash, когда вы просматриваете Интернет со строкой поиска «учебник по массивам bash» (без кавычек ), например

linuxconfig.org/how с -по -использовать -массивы -в -сценарии bash -


Я думаю, что это самые распространенные случаи, когда вы объявляете переменные.


Пожалуйста, обратите внимание, что

  • в функции, declareделает переменную локальной (в функции)
  • без имени, в нем перечислены все переменные (в активной оболочке)

    declare
    

Наконец, вы получаете краткий обзор возможностей оболочки, построенной -в команде declareв bashкомандой

help declare
16
05.02.2020, 14:04

Я попытаюсь объяснить это, но простите меня, если я не последую приведенному вами примеру. Я скорее попытаюсь направить вас по моему собственному, отличному, подходу.

Вы говорите, что уже понимаете такие понятия, как «переменные» и «их расширение» и т. д., поэтому я просто бегло пройдусь по некоторым базовым знаниям, которые в противном случае потребовали бы более глубокого изучения.

Итак, я начну с того, что на самом базовом уровне команда declare— это просто способ сообщить Bash, что вам нужно значение переменной (, т.е. может измениться во время выполнения сценария ), и что вы будете ссылаться на это значение, используя определенное имя, именно то имя, которое вы указываете рядом с самой командой declare.

То есть:

declare foo="bar"

сообщает Bash, что вы хотите, чтобы переменная с именем fooимела значение bar.

Но... подождите минутку... мы можем сделать это вообще без использования declare, не так ли?. Как и в:

foo="bar"

Совершенно верно.

Что ж, получилось так, что приведенное выше простое присваивание на самом деле является неявным способом для... фактически... объявления переменной.

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

Но тогда, если так хорошо возможно объявить «имя, которое будет помечать значения переменных» (просто «переменная» в дальнейшем, для краткости )без использования declare вообще, почему Вы когда-нибудь хотели бы использовать эту напыщенную команду «объявить»?

Ответ заключается в том, что приведенный выше неявный способ объявления переменной (foo="bar"), он… неявно… заставляет Bash считать, что переменная относится к тому типу, который чаще всего используется в типичном сценарии использования для оболочка.

Таким типом является строковый тип, то есть последовательность символов без определенного значения. Следовательно, строка — это то, что вы получаете, когда используете неявное объявление.

Но вам, как программисту, иногда нужно рассматривать переменную как, например, число... над которым нужно выполнять арифметические операции... и использование неявного объявления типаfoo=5+6не будет заставить Bash присвоить fooзначение 11, как и следовало ожидать. Он скорее присвоит fooпоследовательность трех символов 5+6.

Итак... вам нужен способ сообщить Bash, что вы хотите, чтобы fooсчиталось числом, а не строкой... и именно для этого явное declare пригодится.

Просто скажи:

declare -i foo=5+6  # <<- note the '-i' option: it means 'integer'

и Bash с радостью посчитает за вас и присвоит числовое значение 11 переменной foo.

То есть :, говоря declare -i foo, вы присваиваете переменной fooатрибут , являющийся целым числом.

Объявление чисел (именно целыми, потому что Bash до сих пор не понимает десятичные дроби, числа с плавающей запятой и все такое ), может быть первой причиной использования declare, но не единственной причиной. Как вы уже поняли, переменным можно присвоить еще несколько атрибутов. Например, вы можете заставить Bash всегда делать значение переменной в верхнем регистре, несмотря ни на что :, если вы говорите declare -u foo, затем с этого момента, когда вы говорите foo=bar, Bash фактически присваивает строку BARпеременной foo.

Чтобы присвоить какой-либо из этих атрибутов переменной, вы должны использовать команду declare, другого выбора нет.


Еще один из атрибутов, которые вы можете указать через declare, — это печально известный атрибут «name -ref», атрибут -n.(А теперь я собираюсь возобновить концепцию, которую я отложил ранее ).

Имя атрибута -ref, в основном,предоставляет программистам Bash другой способ изменить значение переменной. Точнее, это дает косвенный способ сделать это.

Вот как это работает:

Вы declareпеременная, имеющая атрибут -n, и это очень рекомендуется (хотя и не является строго обязательным, но это упрощает )то, что вы также даете значение это очень изменчиво в той же команде declare. Вот так:

declare -n baz="foo"

Это сообщает Bash, что с этого момента каждый раз, когда вы будете использовать или изменять значение переменной с именем baz, он будет фактически использовать или изменять значение переменной с именем foo.

Это означает, что с этого момента вы можете сказать что-то вроде baz=10+3, чтобы заставить fooполучить значение 13. Предполагая, конечно, что fooранее было объявлено как целое число (declare -i), как мы сделали только один минуту назад, иначе будет получена последовательность из четырех символов10+3.

Также :, если вы измените значение fooнапрямую, как в foo=15, вы также увидите 15, сказав echo “${baz}”. Это связано с тем, что переменная baz, объявленная как имя -ref of foo, всегда отражает значение foo.

Приведенная выше команда declare -nназывается «ссылкой на имя -», потому что она заставляет переменнуюbazссылаться на имя другой переменной. На самом деле мы объявили, что bazимеет значение "foo", которое из-за опции -nобрабатывается Bash как имя для другой переменной.

Итак, с какой стати на Земле вам вообще захотелось это сделать?

Ну.. стоит сказать, что это фича для достаточно продвинутых нужд.

На самом деле настолько продвинутый, что, когда программист сталкивается с проблемой, которая действительно требует имени -ref, вполне вероятно, что такая проблема должна быть решена с использованием соответствующего языка программирования вместо Bash.

Одной из таких дополнительных потребностей является, например, когда вы, как программист, не можете знать во время разработки , какую переменную вам придется использовать в определенном месте скрипта, но это будет полностью известна динамически во время выполнения -. А учитывая, что ни один программист не может вмешиваться во время -выполнения, единственный вариант — предусмотреть заранее такую ​​ситуацию в сценарии, и можно указать «имя -ref». единственный действенный способ. В качестве широко известного варианта использования этой расширенной потребности подумайте, например, о подключаемых модулях -. Программист программы, поддерживающей -плагины, должен заранее предусмотреть общие положения для будущих (и, возможно, сторонних -плагинов )-. Поэтому программисту нужно будет использовать такие средства, как имя -ref в Bash.

Еще одна дополнительная потребность, когда вам приходится иметь дело с огромным объемом данных в ОЗУ, и вам также необходимо передавать эти данные через функции вашего скрипта, которые также необходимо модифицировать. эти данные по пути. В таком случае вы, безусловно, могли бы скопировать эти данные из одной функции в другую (, как это делает Bash, когда вы делаете dest_var="${src_var}"или когда вы вызываете функции, как в myfunc "${src_var}"), но эти данные огромны это приведет к огромной трате ОЗУ и для очень неэффективной работы. Таким образом, Решение в таких ситуациях состоит в том, чтобы использовать не копию данных, а ссылку на эти данные. В Bash имя -ref. Этот вариант использования действительно является нормой для любого современного языка программирования, но он является исключительным, когда речь идет о Bash, потому что Bash в основном предназначен для коротких простых скриптов, которые в основном имеют дело с файлами и внешними командами, и поэтому скрипты Bash редко должны передавать большие объемы данных. количество данных между функциями.А когда функциям скрипта необходимо совместно использовать некоторые данные (, получить к ним доступ и изменить их ), это обычно достигается путем простого использования глобальной переменной, что является нормой в сценариях Bash, хотя и очень устарело в соответствующих языках программирования.

Затем может быть примечательный вариант использования имен -refs в Bash, и (возможно, по иронии судьбы )это связано с использованием других типов переменных:

  1. переменные, объявленные как «индексированные массивы»(declare -a)
  2. переменные, объявленные как «ассоциативные массивы»(declare -A).

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

Если все эти примеры кажутся странными и до сих пор непонятными, то это только потому, что ссылки на имена -действительно являются сложной темой и редко нужны для типичного сценария использования Bash.

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


Кроме того, небольшой личный совет, который на самом деле лучше подходит для комментария, но я не смог сжать его настолько, чтобы он соответствовал ограничениям комментариев StackExchange.

Я думаю, что самое то, что вы должны сделать на данный момент, это просто поэкспериментировать с именами -refs, используя простые примеры, которые я показал, и, возможно, с приведенным вами примером кода, не принимая во внимание на данный момент часть «зачем?» и сосредоточившись только на части «как это работает». Немного поэкспериментировав, часть «как» может лучше укорениться в вашем уме, так что часть «почему» станет ясной для вас в свое время, когда (или если )у вас возникнет реальная практическая задача для которому действительно пригодится имя -ref.

11
27.01.2020, 20:08

Теги

Похожие вопросы