shell 函数和同名变量

Tim*_*Tim 4 bash environment-variables function

Bash 手册

请注意,具有相同名称的 shell 函数和变量可能会导致环境中多个同名条目传递给 shell 的子项。在这可能会导致问题的情况下,应该小心。

bash 如何区分“shell 函数和同名变量”?

$  func () { return 3; }; func=4; declare -p func; declare -f func;
declare -- func="4"
func () 
{ 
  return 3
}
Run Code Online (Sandbox Code Playgroud)

“传递给 shell 子项的环境中的多个同名条目”何时发生?

遇到什么问题应该“注意”什么?

Gil*_*il' 5

一般故事:单独的命名空间

通常,shell 区分变量和函数,因为它们在不同的上下文中使用。简而言之,如果名称出现在 a 之后$,或者作为export(without -f) 和unset(without -f)等内置函数的参数,它就是变量名。名称是如果它显示为(别名扩展之后)的命令或作为一个参数的函数名export -funset -f

变量可以导出到环境中。环境变量的名称与shell变量的名称相同(并且值也相同)。

使用较旧的 bash:由于函数导出而造成的混乱

与大多数其他 shell 不同,Bash 还可以将函数导出到环境中。由于环境中没有类型指示,因此无法识别环境中的条目是否为函数,只能通过分析环境变量的名称或值。

较旧版本的 bash 使用函数名作为名称在环境中存储一个函数,并且将看起来像函数定义的东西作为函数值。例如:

bash-4.1$ foobar () { echo foobar; }
bash-4.1$ export -f foobar
bash-4.1$ env |grep -A1 foobar
foobar=() {  echo foobar
}
bash-4.1$ 
Run Code Online (Sandbox Code Playgroud)

请注意,无法区分其代码是{ echo foobar; }其值是() { echo foobar?}(where?是换行符)的变量的函数。结果证明这是一个糟糕的设计决定。

有时,shell 脚本会使用环境变量调用,其值受潜在敌对实体的控制。例如,CGI 脚本。Bash 的函数导出/导入功能允许以这种方式注入函数。例如执行脚本

#!/bin/bash
ls
Run Code Online (Sandbox Code Playgroud)

只要环境不包含具有特定名称(例如PATH)的变量,来自远程请求就是安全的。但是,如果该请求可以在环境变量设置ls() { cat /etc/passwd; }这时,bash会愉快地执行cat /etc/passwd,因为那是身体ls功能。

使用较新的 bash:混乱大多得到缓解

这个安全漏洞是由Stéphane Chazelas发现的,是Shellshock 漏洞的一个方面。在 bash 的后 Shellshock 版本中,导出的函数由它们的名称而不是它们的内容标识。

bash-4.3$ foobar () { echo foobar; }
bash-4.3$ export -f foobar
bash-4.3$ env |grep -A1 foobar
BASH_FUNC_foobar%%=() {  echo foobar
}
Run Code Online (Sandbox Code Playgroud)

现在没有安全问题,因为像这样BASH_FUNC_foobar%%的名称不常用作命令名称,并且可以被允许传递环境变量的接口过滤掉。在技​​术上可以%在环境变量的名称中包含一个字符(这就是现代 bash 的导出函数工作的原因),但通常人们不会这样做,因为 shell 不接受%变量名称。

bash 手册中的句子指的是旧的(Shellshock 之前的)行为。它应该被更新或删除。对于现代 bash 版本,如果您假设环境变量的名称不以%%.