Почему bash даже разбирает / запускает вещи, помещенные в переменную окружения?

9

Shellshock ошибка в Баш работает путем переменных окружения. Честно говоря, я был удивлен тем, что есть такая особенность, как:

"передача определений функций через env vars"

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

Бонус. У других оболочек зш, тире и т. Д. Тоже есть эта функция?

humanityANDpeace
источник
Он использует переменные env для передачи определений функций. Что вы имеете в виду под «Почему это не просто делает переменные окружения доступными / доступными?» ?
Anthon
@Anthon Спасибо за комментарий. Может быть, я должен быть яснее и перефразировать. По какой причине необходимо иметь возможность передавать определения функций через env vars?
человечествоANDpeace
1
Я не уверен на 100%, но я думаю, что, например, именно так GNU parallelраспространяет определения функций, если он вызывает несколько экземпляров bash. Если бы не таким образом, он должен был бы записать их в файл, который будет считывать каждый вызванный экземпляр, и тогда вам придется иметь дело с такими проблемами, как, когда этот файл может быть удален.
Anthon
2
эта тема имеет некоторую историю. экспортированные функции, тем не менее, безумны . если вы хотите, чтобы новая оболочка унаследовала старые исполняемые команды оболочки, вы должны использовать .dotтот же файл, что и старая оболочка. Вот как это делается - и это имеет смысл - или вы передаете новой оболочке файл в качестве ввода при execзагрузке. как только он будет прочитан, файл все равно кэшируется ядром.
mikeserv
@ mikeserv Правильно ли я понимаю, что большая часть ракушки связана с этой функцией, которая в любом случае не так важна?
человечествоANDpeace

Ответы:

4

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

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

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

Экспортируемые функции - старая особенность. Функции были добавлены в оболочку Bourne в SVR2 , а экспортированные функции были добавлены в оболочку версии 8 в том же году (1984). В этой оболочке переменные и функции использовали одно и то же пространство имен. Я не знаю, как работал экспорт функций. Heirloom оболочки основана на варианте Bourne , который имеет функции , но не экспортировать их.

ATT ksh предположительно поддерживает экспорт функций, но, глядя на источник или играя с ним, я не вижу, что он делает, начиная с ksh93u.

env -i /usr/bin/ksh -c 'f=variable; f () { echo function; }; typeset -fx f; /usr/bin/env; ksh -c f'
_=*25182*/usr/bin/env
PWD=/home/gilles
SHLVL=1
A__z="*SHLVL
ksh: f: not found

Общедоступные клоны Ksh (pdksh, mksh), dash и zsh не поддерживают функции экспорта.

Жиль "ТАК - перестань быть злым"
источник
1
благодарю вас! Таким образом, без экспорта функций функциональность теряется, но есть некоторые оболочки, такие как dash, zsh, pdksh и т. Д., В которых отсутствует эта функциональность, я правильно понял?
человечествоANDpeace
Но когда я экспортирую функцию в bash, она переходит в переменную вроде BASH_FUNC_f%%=() { echo hi }. Зачем bash анализировать другие переменные окружения? С чего бы это даже разбирать, BASH_FUNC_g%%когда я только звоню f? (По-видимому, до выстрела, переменная окружения только что была вызвана fили g- но я все еще задаюсь вопросом, почему gбыл бы проанализирован, если бы я никогда не вызывал gв моем сценарии)
Метаморфический
@Met Нужно посмотреть на все переменные окружения, чтобы выяснить, какие из них являются определениями функций. Он может запомнить этот факт и избежать синтаксического анализа кода функции до тех пор, пока он не понадобится в первый раз, но это будет дополнительной сложностью при очень небольшом выигрыше. Проще иметь только один тип функции, а не два («обычная функция» и «функция из переменной окружения, которая требует небольшого разбора»).
Жиль "ТАК - перестать быть злым"
Не ясно. Я полагаю, что очевидной вещью было бы, когда я запускаю что-то под названием f: (1) проверка на вызываемую функцию оболочки f, (2) проверка на вызываемую переменную окружения fи попытка ее проанализировать, (3) проверка каждый PATHкомпонент для исполняемого файла называется f. Каким образом анализ каждой переменной среды в виде шелл-кода при запуске может показаться менее сложным?
Метаморфизм
@Metamorphic Вы предлагаете добавить еще один шаг, который должен выполняться в каждой команде. Вам также придется добавить еще один шаг при определении или отмене определения функций (после того unset -f foo, как bash больше не должен искать определение функции fooв среде), при перечислении функций (как вы обрабатываете, declare -fкроме чтения всех переменных среды?) и о чем еще я не думаю. Ваш дизайн кажется более легким, потому что вы оставили большую его часть. Напротив, все, что запускается при запуске, представляет собой один кусок кода, и после этого все просто работает.
Жиль "ТАК ... перестать быть злым"