分类: LINUX
2010-02-26 20:35:54
Internally, for forking, Bash stores the function definitions in environment variables. Variables with the content ”() ....”.
Something like the following works without “officially” declaring a function:
$ export testfn="() { echo test; }"
$ bash -c testfn
test
$
似乎是bash的一个undocumented的特性, 对这一特性的试验继而让我对bash中的变量管理困惑不已, 通过gdb
一个调试版的bash终于把它搞明白, 这一过程中发生了很多诡异的事情:
* export testfn='() { echo test; }'
会在当前shell的环境变量中加入一项, 与普通A=B的变量无异, 注意这里说"环境变量"时, 是指任何一个进程
都会有的一个环境块, 不要与bash中非环境普通变量混淆.
* bash -c testfn
产生的新进程: 那个子bash, 从此开始, 就有一堆奇怪的事情:
echo $testfn
你看不到这个环境变量, 一般配置下, 输入
echo $testf 此时按会补齐这个环境变量名, 这是readline做的事, 但readline也不没有补齐, 这是怎么
回事?
type testfn
会看到在子bash中, 有一个testfn函数:
testfn is a function
testfn ()
{
echo test
}
至此, 你可能以为子bash对环境变量parse之后识别出这种特殊形式, 进而把它定义为一个函数, 同时把它
从环境变量中删除了.
但是, 它并未从环境变量中被删除:
env 或 printenv
可以看到它, 取值竟与父bash中略有不同, 把';'换成了一个换行符. 我一开始很怀疑是env 或 printenv 的问题,
但查看了coreutils中 printenv的源码后打消了我的疑惑, 代码很短, 直接显示所有的environ内容.
所以, 问题是出在bash!, 把bash的源代码抓回来, 发现靠静态地跟踪对这个问题的处理比较困难, 在variables.c
的unbind_func上加了断点, 证实了猜测:
unset -f testfn
时, 貌似只删除函数, 但同时也删除了作为该函数来源的环境变量, 这算什么事! 系统环境变量与函数名被bash
搞得如此混乱.
待续...