Обработка переменных и область видимости в оболочке и особенно bash
могут быть очень неясными и неинтуитивными (и иногда содержать ошибки ).
ksh
имел typeset
для аналогичной функции. ksh
, zsh
, yash
имеют typeset
. bash
имеет typeset
как псевдоним declare
для совместимости с ksh
, zsh
имеет declare
как псевдоним typeset
для совместимости с bash
. Большинство оболочек имеют export
, readonly
и local
, которые реализуют часть того, что делает typeset
.
Одной из причин, почему bash
авторы выбрали declare
вместо typeset
, может быть то, что typeset
не только устанавливает тип, но также объявляет переменную :вводит ее в заданная область, возможно, с типом, атрибутами и/или значением.
В bash
переменные могут быть:
declare
)Они могут быть разных типов:
и иметь несколько атрибутов:
(хотя различие между типом и атрибутом может быть довольно размытым ).
Не все комбинации типов и атрибутов поддерживаются или эффективны.
Теперь declare
объявляет переменную в текущей области. bash
, несмотря на то, что он реализует динамическую область видимости, внешняя -область видимости обрабатывается особым образом. Он называет это глобальной областью .
declare
ведет себя совершенно по-разному, когда вызывается в этой глобальной области видимости и когда в функции (я не говорю о той отдельной области видимости, которая вводится подоболочками или связана с окружением ). ].
Когда вы выполняете declare var
внутри функции и при условии, что та же переменная не была объявлена в той же области видимости, она объявляет новую новую переменную, которая изначально не установлена и скрывает потенциальную var
переменную, которая должна была присутствовать в родительской области (вызывающей функции ).
Это динамическая область видимости, реализованная через своего рода стек. Когда функция завершается, статус, тип, атрибуты и значение переменной, какими они были при вызове функции, восстанавливаются (и извлекаются из стека ).
Однако вне любой функции (в глобальной области видимости ), declare
объявляет переменную, но не инициализирует ее как неустановленную, если она была установлена до (так же, как при использовании declare
a второй раз в той же области действия функции ). Если указан тип, значение переменной может быть преобразовано, хотя разрешены не все пути преобразования (, только скалярное преобразование в массив/хэш ), а атрибуты могут быть добавлены или удалены.
В bash
функция declare -g
воздействует на переменную в нижней части стека во внешней -самой ("глобальной" )области видимости.
declare -g
был вдохновлен ksh93
typeset -g
. Но ksh93
реализует статическую область видимости, где глобальная область видимости отличается и отделена от области видимости каждой функции. Делать то же самое с динамической областью видимости не имеет большого смысла. Во всех других оболочках, которые имеют typeset -g
(mksh
, zsh
, yash
), typeset -g
, используется для изменения некоторого атрибута переменной без создания нового локального экземпляра.
В bash
люди обычно используют его для той же цели,но поскольку это влияет на переменную внешней -большей области, а не на текущую переменную, это не всегда работает.
Например:
integer() { typeset -gi "$1"; }
Чтобы сделать переменную целочисленной, используйте mksh
/ yash
/ zsh
. В bash
он работает только с переменными, которые не были объявлены локальными вызывающим кодом:
$ bash -c 'f() { declare a; integer a; a=1+1; echo "$a"; }; integer() { typeset -gi "$1"; }; f'
1+1
$ bash -c 'f() { integer a; a=1+1; echo "$a"; }; integer() { typeset -gi "$1"; }; f'
2
Обратите внимание, что export var
не является ни typeset -x var
, ни typeset -gx var
. Он добавляет атрибут export
без объявления новой переменной, если переменная уже существует. То же самое для readonly
против typeset -r
.
Также обратите внимание, что unset
в bash
отменяет установку переменной только в том случае, если она была объявлена в текущей области видимости (оставляет ее объявленной, за исключением глобальной области видимости; он удаляет атрибуты и значения, и переменная больше не является массивом или хэшем; также обратите внимание, что в namerefs сбрасывается указанная переменная ). В противном случае он просто извлекает один переменный слой из стека, упомянутого выше. В bash
5.0 или выше это можно исправить, установив параметр localvar_unset
.
Подводя итоги:
declare var
При вызове в функции и если var
не было объявлено ранее в той же функции, объявляет переменную типа скалярная без атрибутов, которая изначально не установлена.
При вызове вне какой-либо функции или если var
уже было объявлено в той же функции, это не имеет никакого эффекта, поскольку мы не указываем никакого нового типа или атрибута.
declare -g var
Где бы он ни вызывался, он объявляет var
во внешней -самой ("глобальной" )области :делает его объявленным типа скалярного ], без атрибута, без значения, если он был ранее неизвестен в этой области (, которая по всем намерениям и целям аналогична неизвестной переменной, за исключением того, что она будет отображаться в выходных данныхtypeset -p
)или ничего не делать в противном случае.
В любом случае,вы не сможете получить доступ к этой переменной в контексте, в котором вы выполняете эту команду:
f() { local a; g; }; g() { typeset -g a=123; echo "$a"; }; f
ничего не выводит.
Первый вход в CLI, нажмите ctrl+alt+f1
или f2
, затем войдите в систему под своим пользователем, затем попробуйте выполнить следующие действия:
нашел эту ошибку здесь:
https://bugzilla.redhat.com/show_bug.cgi?id=1149893
В частности, сюда необходимо поместить файл.rule,
/etc/polkit-1/rules.d/
(добавьте имя файла и просто дайте расширение.rules)
приведите ниже правила:
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.color-manager.create-device" ||
action.id == "org.freedesktop.color-manager.create-profile" ||
action.id == "org.freedesktop.color-manager.delete-device" ||
action.id == "org.freedesktop.color-manager.delete-profile" ||
action.id == "org.freedesktop.color-manager.modify-device" ||
action.id == "org.freedesktop.color-manager.modify-profile") &&
subject.isInGroup("username")) {
return polkit.Result.YES;
}
});
Затем вам нужно заменить слово «имя пользователя» на группу вашего пользователя.