что такое zsh-эквивалент экспорта bash -f

24

Итак, я начал использовать zsh. Мне нравится все в порядке. Это выглядит очень круто и гладко, и тот факт, что текущий рабочий каталог и фактическая командная строка находятся на разных строках, это хорошо, но в то же время я замечаю, что это zshможет быть немного медленнее, чем bash, особенно при печати текста в экран.

Больше всего мне понравилось то, что он zshбыл «обратно совместим» со всеми функциями, которые я определил в своих .bashrc.

Хотя одна схватка. Все функции работают отлично, но я не могу понять, как работает система экспорта.

У меня были .bashrcэкспортированы некоторые из этих функций, чтобы я мог использовать их в другом месте, например, в скриптах и ​​внешних программах export -f.

В zsh об экспорте даже не говорят. Это автозагрузка? Эти две вещи одинаковы? Мне тяжело понять это.

ixtmixilix
источник
2
Это очень старый вопрос, но я хочу сказать, что «текущий рабочий каталог и фактическая командная строка находятся на разных строках» не имеет никакого отношения к zsh. Это зависит от того, как вы настроили свою подсказку, вот и все.
4ae1e1

Ответы:

11

Переменные окружения, содержащие функции, являются взломом bash. У Zsh нет ничего похожего. Вы можете сделать что-то подобное с несколькими строками кода. Переменные окружения содержат строки; более старые версии bash, до обнаружения Shellshock , хранили код функции в переменной, имя которой совпадает с именем функции, а за значением () {следует код функции, после которого следует }. Вы можете использовать следующий код, чтобы импортировать переменные с этой кодировкой и попытаться запустить их с настройками, подобными bash. Обратите внимание, что zsh не может эмулировать все функции bash, все, что вы можете сделать, это немного приблизиться (например, чтобы $fooразделить значение и расширить подстановочные знаки, а также сделать массивы на основе 0).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Как отметил Стефан Шазелас , первооткрыватель Shellshock, более ранняя версия этого ответа могла выполнить произвольный код на этом этапе, если определение функции было некорректно. это может быть функция, импортированная из среды.)

Версии bash после Shellshock кодируют функции в среде, используя недопустимые имена переменных (например BASH_FUNC_myfunc%%). Это затрудняет их надежный анализ, поскольку zsh не предоставляет интерфейс для извлечения таких имен переменных из среды.

Я не рекомендую делать это. Полагаться на экспортируемые функции в скриптах - плохая идея: это создает невидимую зависимость в вашем скрипте. Если вы когда-либо запускаете свой сценарий в среде, в которой нет вашей функции (на другом компьютере, в задании cron, после изменения файлов инициализации оболочки…), ваш сценарий больше не будет работать. Вместо этого сохраните все свои функции в одном или нескольких отдельных файлах (что-то вроде ~/lib/shell/foo.sh) и запустите свои сценарии, импортировав функции, которые он использует ( . ~/lib/shell/foo.sh). Таким образом, если вы измените foo.sh, вы можете легко найти, какие сценарии полагаются на него. Если вы скопируете скрипт, вы легко сможете узнать, какие вспомогательные файлы ему нужны.

Zsh (и ksh перед ним) делает это более удобным, предоставляя способ автоматической загрузки функций в сценарии, где они используются. Ограничением является то, что вы можете поместить только одну функцию в файл. Объявите функцию как автозагрузку и поместите определение функции в файл, именем которого является имя функции. Поместите этот файл в каталог, указанный в $fpath(который вы можете настроить через FPATHпеременную окружения). В вашем скрипте объявите автозагрузку функций с помощью autoload -U foo.

Кроме того, zsh может компилировать скрипты, чтобы сэкономить время на анализ. Звоните, zcompileчтобы скомпилировать скрипт. Это создает файл с .zwcрасширением. Если этот файл присутствует, то autoloadзагрузит скомпилированный файл вместо исходного кода. Вы можете использовать zrecompileфункцию для (пере) компиляции всех определений функций в каталоге.

Жиль "ТАК - перестань быть злым"
источник
1
Забавно, что ваш код имеет ту же уязвимость, bashчто и шелл-шок (не проверяет, что содержимое переменной является только определением функции, и обрабатывает любое имя переменной, например HTTP_HOSTили LC_X). Хороший ответ иначе.
Стефан
@ StéphaneChazelas Если вы собираетесь запускать команды с функциями, импортированными из среды, вы в значительной степени проиграли. Но я обновил код импорта, чтобы не выполнять произвольный код. Это не очень полезно, так как пост-шеллшок bash не кодирует экспортируемые функции таким же образом.
Жиль "ТАК ... перестать быть злым"
Вы исправили эквивалент CVE-2014-6271, но все еще, вероятно, подвержены множеству уязвимостей типа CVE-2014-6277 / 6278 ... так как вы по-прежнему подвергаете анализатор zsh коду в любой переменной в том числе те , которые являются потенциально под контролем злоумышленников в некоторых контекстах (как код в zsh -c 'functions[f]=$VAR' это анализируется , даже если fфункция не вызывается). Решение состоит в том, чтобы рассматривать только переменные, имена которых следуют за зарезервированным шаблоном, как те $BASH_FUNC_x%%, но, как вы говорите, zshне имеют API для их перечисления или извлечения. Вам нужно позвонить, perlнапример.
Стефан
7

Если вы поместите объявление своей функции в .zshenv , ваша функция будет использоваться из скрипта без каких-либо усилий.

рулетики
источник
Почему вы опровергли мой ответ? Пожалуйста, объясни.
Рул
Все еще жду ответа и все еще работаю!
Рул
Я только что обнаружил этот ответ, и это идеальное решение.
AFH
Я не отрицал это. И TBH ОП спрашивал об экспорте вещей из .bashrc, что является плохой идеей, лучше поместить это в сценарий, чтобы не оказаться в огромной среде. Но ваше решение - всего лишь вариант той же самой плохой идеи: вставьте все свои сценарии, .zshenvи оно замедляет каждый вызов zsh, анализируя большой объем кода, который никогда не используется. Кроме того, это не то же самое, что экспорт функции, как экспортируемая переменная, экспортированная функция доступна только для дочерних процессов. В то время как материал, который вы вставляете, .zshenvдоступен каждому zsh.
Метаморфизм
Наконец, если вы полагаетесь на свой личный код .zshenv, то все ваши скрипты будут полностью непереносимыми. Обычно сценарии могут зависеть друг от друга, и это нормально, вы распространяете их вместе. Но если они зависят от наличия специальных функций .zshenv, никто не захочет их использовать, или они должны будут вызываться со специальными функциями ZDOTDIR, предотвращающими выполнение ваших собственных функций .zshenv. Это будет боль.
Метаморфический