5

从 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 使用特殊命名的 shell 标识符来存储函数。当通过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罪魁祸首吗?!

4

2 回答 2

5

TL;DR:已知dash问题;灰色区域,可能是固定的;最好不要依赖非 bash 父母的出口。

这是由破折号 0.5.8 的变化引起的;cp。dash 从环境中删除导出的 bash 函数

目前还没有达成共识是否会解决这个问题。POSIX 似乎允许删除无效的环境条目,其他(更模糊的)shell 显然也这样做,但它会在各种应用程序中引起问题,特别是因为在 Ubuntu/bin/sh中符号链接到dash(因此是默认 shell)。


我的个人用例是一些简短的实用程序函数,我在我~/.profile的 . 其中一个在自动启动的Conky守护程序中运行,并且由于自动启动通过dash. 我可以解决这个问题。Korn shell的FPATH自动加载机制在 Bash 中也很不错......

于 2016-06-30T14:14:56.110 回答
1

这并不理想,但您可以在 Dash 中定义您的函数:

$ foo() { echo "foobar"; }
$ dash -c "$(declare -f); foo"
foobar
于 2017-02-26T16:17:23.463 回答