Регрессия: Экспортированная функция Bash потеряна после прохождения другого процесса
При переходе с Ubuntu 14.04 на 16.04 я заметил, что некоторые из моих скриптов Bash не работают из-за отсутствия экспортируемых функций. Интересно, связано ли это с исправлениями ошибки Shellshock, хотя я просто export -f
функции, и не полагаясь на представление внутренней функции Bash. Ошибка не происходит в прямой подоболочке Bash, только если между ними есть другой процесс. Например, Bash вызывает awk / Perl / Vim, вызывая другой Bash. Вот пример с Perl:
Хорошо
$ foo() { echo "foobar"; }
$ export -f foo
$ export -f; foo
foo ()
{
echo "foobar"
}
declare -fx foo
foobar
$ bash -c "export -f; foo"
foo ()
{
echo "foobar"
}
declare -fx foo
foobar
$ perl -e 'system("bash -c \"export -f; foo\"")'
foo ()
{
echo "foobar"
}
declare -fx foo
foobar
$ echo $BASH_VERSION
4.3.11(1)-release
Плохой
$ foo() { echo "foobar"; }
$ export -f foo
$ export -f; foo
foo ()
{
echo "foobar"
}
declare -fx foo
foobar
$ bash -c "export -f; foo"
foo ()
{
echo "foobar"
}
declare -fx foo
foobar
$ perl -e 'system("bash -c \"export -f; foo\"")'
bash: foo: command not found
$ echo $BASH_VERSION
4.3.42(1)-release
Я что-то не так делаю, или это ошибка?
Редактировать: @chepner указал, что Bash использует специально названные идентификаторы оболочки для хранения функций. При прохождении dash
(0.5.8-2.1ubuntu2, работает с 0.5.7-4ubuntu1), эти идентификаторы удалены. С ksh
, они остаются в живых. Я проверил с
$ dash
$ sudo strings /proc/$$/environ | grep foo # Still passed from Bash to Dash
BASH_FUNC_foo%%=() { echo "foobar"
$ bash
$ sudo strings /proc/$$/environ | grep foo # But went missing from Dash to Bash
$ exit
$ exit
$ ksh
$ sudo strings /proc/$$/environ | grep foo
BASH_FUNC_foo%%=() { echo "foobar"
$ bash
$ sudo strings /proc/$$/environ | grep foo # Kept from Ksh to Bash
BASH_FUNC_foo%%=() { echo "foobar"
Аналогично, поведение Vim можно изменить с помощью :set shell=/bin/bash
/ :set shell=/bin/ksh
Итак, это dash
обвинять?!
2 ответа
TL;DR: известный dash
проблема; серая зона, может быть исправлена; лучше не полагаться на экспорт, переживший не-bash родителей.
Это вызвано изменением в тире 0,5,8; ср. dash удаляет экспортированные функции bash из среды.
Пока нет единого мнения, будет ли это исправлено. POSIX, кажется, позволяет удалять недопустимые записи среды, другие (более неясные) оболочки, по-видимому, также делают это, но это вызывает проблемы в различных приложениях, особенно потому, что /bin/sh
символическая ссылка на dash
(и, следовательно, оболочка по умолчанию) в Ubuntu.
Мой личный пример использования - это несколько коротких служебных функций, которые я вставил в свой ~/.profile
и который я упоминаю в некоторых сценариях оболочки. Один из них запускается в демоне Conky с автоматическим запуском, а другой пропускает функции, потому что автозапуск происходит через dash
, Я могу обойти это. FPATH
Механизм автозагрузки из оболочки Korn тоже неплохо бы иметь в Bash...
Это не идеально, но вы можете определить свои функции внутри Dash:
$ foo() { echo "foobar"; }
$ dash -c "$(declare -f); foo"
foobar