функции оболочки и переменные с тем же именем

Из руководства Bash :

Обратите внимание, что функции оболочки и переменные с тем же именем могут привести к тому, что в среде, переданной дочерним элементам оболочки, будут отображаться несколько одинаково названных записей. Следует проявлять осторожность в тех случаях, когда это может вызвать проблемы.

Как можно отличить bash «функции оболочки и переменные с тем же именем»?

$ func () { return 3; }; func=4; declare -p func; declare -f func; declare -- func="4" func () { return 3 } 

Когда происходит «множественные идентично именованные записи в среде, переданные детям-оболочкам»?

Какую «заботу» следует принимать по какой-то проблеме?

Благодарю.

2 Solutions collect form web for “функции оболочки и переменные с тем же именем”

Общая история: отдельные пространства имен

Обычно оболочки различают переменные и функции, потому что они используются в разных контекстах. В двух словах имя является именем переменной, если оно появляется после $ или в качестве аргумента для встроенных компонентов, таких как export (без -f ) и unset (без -f ). Имя – это имя функции, если оно появляется как команда (после расширения псевдонима) или в качестве аргумента для export -f , unset -f и т. Д.

Переменные могут быть экспортированы в среду. Имя переменной среды совпадает с переменной оболочки (и значения одинаковы).

С более старым bash: путаница из-за экспорта функций

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

Старые версии bash сохраняют функцию в среде, используя имя функции как имя, и то, что выглядит как определение функции как значение функции. Например:

 bash-4.1$ foobar () { echo foobar; } bash-4.1$ export -f foobar bash-4.1$ env |grep -A1 foobar foobar=() { echo foobar } bash-4.1$ 

Обратите внимание, что невозможно отличить функцию, код которой { echo foobar; } { echo foobar; } из переменной, значение которой равно () { echo foobar␤} (где – символ новой строки). Это оказалось плохим дизайнерским решением.

Иногда скрипты оболочки вызываются с переменными среды, значение которых находится под контролем потенциально враждебного объекта. CGI-скрипты, например. Функция экспорта / импорта функции Bash позволила таким образом впрыскивать функции. Например, выполнение скрипта

 #!/bin/bash ls 

от удаленного запроса является безопасным, если среда не содержит переменные с определенным именем (например, PATH ). Но если запрос может установить переменную среды ls в () { cat /etc/passwd; } () { cat /etc/passwd; } тогда bash с удовольствием выполнит cat /etc/passwd так как это тело ls функции.

С новым bash: путаница в основном облегчается

Эта уязвимость безопасности была обнаружена Стефаном Чазеласом как один из аспектов ошибки Shellshock . В версиях bash post-Shellshock экспортируемые функции идентифицируются по их имени, а не по их содержимому.

 bash-4.3$ foobar () { echo foobar; } bash-4.3$ export -f foobar bash-4.3$ env |grep -A1 foobar BASH_FUNC_foobar%%=() { echo foobar } 

В настоящее время проблема безопасности отсутствует, поскольку такие имена, как BASH_FUNC_foobar%% , обычно не используются в качестве имен команд и могут быть отфильтрованы с помощью интерфейсов, которые позволяют передавать переменные среды. Технически возможно иметь символ % в имени переменной среды (это то, что делает современные экспортируемые функции bash), но обычно люди этого не делают, потому что оболочки не принимают % от имени переменной.

Предложение в руководстве bash относится к старому (pre-Shellshock) поведению. Он должен быть обновлен или удален. В современных версиях bash в среде нет никакой двусмысленности, если вы предполагаете, что переменные окружения не будут иметь имя, заканчивающееся на %% .

Подобное происходит в Emacs Lisp. Он имеет два пространства имен: один для функций и один для переменных. Если вы разыщите символ в контексте функции ( (var) ), он вызовет функцию, если вы отмените ее в контексте переменной ( var ie без скобок), она даст вам переменную. Например:

 (defun myvar (myvar) "adds 3 to MYVAR" (+ 3 myvar)) (setq myvar 7) (message (myvar myvar)) 

myvar функцию myvar с аргументом 7 который является разыменованием переменной myvar .

Это может стать очень запутанным, если вы к нему не привыкли.

Посмотрев на ваш вопрос и сделав тесты для bash, я удивлен, что он представляет такое же поведение. Перевод ELisp сверху в bash:

 [grochmal@phoenix ~]$ myvar () { echo $(($1+3)); } [grochmal@phoenix ~]$ myvar=7 [grochmal@phoenix ~]$ myvar $myvar 10 

Bash немного менее запутанным в этом, чем ELisp, потому что вам нужно значение $ для обозначения переменной. Тем не менее, это может выглядеть как declare одного имени, содержащего две вещи. Видеть:

 [grochmal@phoenix ~]$ declare -p myvar declare -x myvar="7" [grochmal@phoenix ~]$ declare -f myvar myvar () { echo $(($1+3)) } 

(PS Когда вы привыкнете к существованию двух пространств имен, например, вы некоторое время программируете в ELisp, это перестает запутываться)

  • изменить пользовательские системные переменные (число) удаленной серверной машины с помощью ssh?
  • Systemd bash builtins
  • Экспортированные функции bash иногда видны с Perl
  • Полный вид того, где переменная PATH задана в bash
  • При запуске программы запускаются программы .bashrc?
  • Как отменить экспорт DISPLAY в Linux?
  • Переменная среды PATH
  • Изменить каталог команды
  • В чем смысл «_ =»?
  • export -f в .bashrc после обновления до bash 4.3.30 убивает встроенных?
  • Как изменить текстовый редактор по умолчанию в дистрибутиве Debian (сжатие)
  • Linux и Unix - лучшая ОС в мире.