Ing*_*kat 5 bash shellshock-bash-bug dash-shell
从 Ubuntu 14.04 迁移到 16.04 时,我注意到我的几个 Bash 脚本由于缺少导出的函数而失败。我想知道这是否与Shellshock 错误的修复有关,即使我只是简单export -f的函数,而不是依赖 Bash 内部函数表示。失败不会发生在直接的 Bash 子 shell 中,只有在两者之间有另一个进程时才会发生。例如,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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
我做错了什么,还是这是一个错误?
编辑:@chepner 指出 Bash 使用特殊命名的 shell 标识符来存储函数。当通过dash(0.5.8-2.1ubuntu2, working with 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"
Run Code Online (Sandbox Code Playgroud)
同样,Vim 的行为可以通过:set shell=/bin/bash/改变:set shell=/bin/ksh
所以,是dash罪有应得?!
TL;DR:已知dash问题;灰色区域,可能是固定的;最好不要依赖于非 bash 父母的出口。
这是由 dash 0.5.8 的变化引起的;cp。dash 从环境中删除导出的 bash 函数。
是否会修复此问题尚未达成共识。POSIX 似乎允许删除无效的环境条目,其他(更晦涩的)shell 显然也可以这样做,但它会在各种应用程序中引起问题,尤其是因为/bin/sh符号链接到dash(因此是默认 shell)在 Ubuntu 中。
我的个人用例是一些简短的实用程序函数,我已将它们放入我的~/.profile,并在一些 shell 脚本中引用。其中一个在自动启动的Conky守护进程中运行,而那个错过了功能,因为自动启动是通过dash. 我可以解决这个问题。FPATHKorn shell的自动加载机制在 Bash 中也很不错......