Я стремлюсь понять общую концепцию «переменных атрибутов», надеясь, что это поможет мне понятьчто такое декларация в Bash.
Что такое атрибут переменной? Зачем кому-то может понадобиться присвоить атрибут переменной? Почему простого создания переменных и их расширения при выполнении недостаточно при работе с переменными?
решение1
Обычно переменная — это место для хранения значения. Вы присваиваете значение переменной ( var="some value"
), и после этого вы можете вызвать значение с помощью расширения переменной (запись "$var"
эквивалентна записи "some value"
).
Можно создать переменные, которые делают что-то особенное, когда вы присваиваете им значение или в других обстоятельствах, когда оболочка обращается к переменным. Атрибут переменной — это аннотация, которую оболочка сохраняет рядом с именем и значением переменной, что сообщает оболочке о необходимости применять это особое поведение.
Один пример
declare -i x
сообщает оболочке, что x
должно содержать только целочисленные значения. Обычно, когда вы присваиваете значение переменной, оболочка берет строку, которая получается в результате расширения правой части знака равенства, и сохраняет ее как значение переменной. Но если переменная имеет атрибут integer, оболочка анализирует эту строку как арифметическое выражение и сохраняет результат вычисления этого выражения. Например:
$ x=2+2; echo $x
2+2
$ declare -i x; x=2+2; echo $x
4
$ declare -i x; x=2+hello; echo $x
2
$ declare -i x; x=2+
bash: 2+: syntax error: operand expected (error token is "+")
(Третья строка с x=2+hello
установками x
в 2, поскольку hello
это имя переменной, которое не определено, а неустановленные переменные по умолчанию молча интерпретируются как 0.)
Еще примеры
declare -l var
объявляет, чтоvar
должно содержать только строчные буквы. Когда оболочка сохраняет значение переменной, она преобразует любую заглавную букву в строчную.declare -u var
выполняет преобразование в обратном направлении.declare -r var
делает егоvar
доступным только для чтения, что также является особым поведением присваивания: оно приводит к тому, что каждое последующее присваивание завершаетсяvar
неудачей.declare -x var
вызываетvar
экспорт в среду. Для этого атрибута особое поведение происходит, когда bash запускает внешнюю команду: внешние команды видят среду, содержащую переменные, которые оболочка экспортирует в то время, когда оболочка запускает внешнюю команду.
решение2
От help declare
:
Options which set attributes:
-a to make NAMEs indexed arrays (if supported)
-A to make NAMEs associative arrays (if supported)
-i to make NAMEs have the `integer' attribute
-l to convert the value of each NAME to lower case on assignment
-n make NAME a reference to the variable named by its value
-r to make NAMEs readonly
-t to make NAMEs have the `trace' attribute
-u to convert the value of each NAME to upper case on assignment
-x to make NAMEs export
Примечание: declare
также может использоваться для функций.
Каждый из этих атрибутов имеет одно или несколько применений:
-a
- для создания индексированных массивов NAME (если поддерживается)
Это не совсем необходимо, поскольку установка параметра как массива автоматически объявит его как индексированный массив. Использование этого может сделать ваш код более очевидным и читаемым.
-A
- для создания ассоциативных массивов NAME (если поддерживается)
Насколько мне известно, это совершенно необходимо, поскольку попытка задать ассоциативный массив без предварительного его объявления приведет к созданию индексированного массива.
$ assoc=([foo]=bar)
$ declare -p assoc
declare -a assoc=([0]="bar")
$ unset assoc
$ declare -A assoc
$ assoc=([foo]=bar)
$ declare -p assoc
declare -A assoc=([foo]="bar" )
-i
- чтобы ИМЕНА имели атрибут `integer'
Полезно, если вы хотите убедиться, что ваш параметр можеттолькохранить целые числа. Это также позволяет выполнять арифметическое расширение при присваивании.
$ declare -i a
$ a=foo
$ echo $a
0
$ a=1+1
$ echo $a
2
-l
- для преобразования значения каждого ИМЕНИ в нижний регистр при назначении
Гарантирует, что значение ваших параметров всегда будет в нижнем регистре. Это довольно крутая функция, о которой я не знал и, вероятно, буду использовать в будущем. Она устраняет необходимость в сложном расширении параметров или использовании отдельной утилиты, такой какtr
$ declare -l foo=Bar
$ echo $foo
bar
-n
- сделать NAME ссылкой на переменную, названную по ее значению
Как косвенная ссылка. Это может исключить использование eval
во многих сценариях.
$ a=foo
$ declare -n b=a
$ echo $b
foo
-r
- сделать ИМЕНА доступными только для чтения
Это хорошая функция. Она может быть особенно полезна для переменных оболочки/окружения, которые вы хотите установить один раз и убедиться, что они не будут изменены.
$ declare -r foo=bar
$ echo $foo
bar
$ foo=baz
-bash: foo: readonly variable
-t
- чтобы ИМЕНА имели атрибут `trace'
Я не уверен насчет этого. Я думаю, это может применяться только к функциям.
-u
- для преобразования значения каждого ИМЕНИ в верхний регистр при назначении
Похож на -l
, но противоположен
$ declare -u foo=bAr
$ echo $foo
BAR
-x
- сделать так, чтобы ИМЕНА экспортировались
Еще один способ экспортировать переменные в среду.