POSIX Shell中函数和变量的独立命名空间


13

在破折号中,函数和变量似乎位于单独的命名空间中:

fn(){
    fn="hello world"
}
fn; echo "The value is $fn!" #prints: The value is hello world!
fn; echo "The value is $fn!" #prints: The value is hello world!
#the fn variable doesn't conflict with the fn function

这是破折号专用功能还是POSIX保证?


2
您的代码实际上并不能证明该fn函数位于单独的命名空间中。如果执行一次删除了其定义,我们将看到完全相同的行为。您应该显示该函数仍处于定义状态,例如type fn之后。
亚历克西斯

Answers:


13

保证

2.9.5功能定义命令

函数是用户定义的名称,用作简单命令以使用新的位置参数调用复合命令。通过“功能定义命令”定义功能。[...]

该函数名为fname; 应用程序应确保它是一个名称(请参阅XBD名称),并且不是特殊内置实用程序的名称。一个实现可以允许函数名称中的其他字符作为扩展名。实现应为函数和变量维护单独的名称空间。


还要注意,unset必须使用-v-f在通过给定名称取消设置变量或函数之间进行选择。bash(与大多数其他shell相对)将在没有变量(!)的情况下取消设置foo 功能unset foo这是fooPOSIX允许的行为。这就是为什么在POSIX脚本中始终使用-v或的好习惯-f(当然,在bash脚本中也是如此,但是请注意,unset可能不会总是在中取消设置变量bashbash变量作用域存在很多问题)。
斯特凡Chazelas

请注意,在shellshock之前的bash中,以给定名称导出变量和函数时会遇到问题,因为bash最终会为两个名称使用相同的环境变量名(在环境中两次输入,某些命令可能会删除其中之一)
斯特凡Chazelas

8

变量和函数位于破折号中的不同名称空间中,这也由POSIX指定:

实现应为函数和变量维护单独的名称空间。

除此之外,默认情况下,变量具有全局作用域。一些外壳程序(例如bash,ksh和zsh)提供local关键字以仅在具有局部范围的函数中声明变量。

因此,是的,POSIX保证了您看到的行为。

POSIX还没有规范 local

早期建议中对功能的描述是基于这样的观念,即功能应像微型shell脚本一样运行。也就是说,除了共享变量外,执行环境中的大多数元素都应表现为好像是新的执行环境,[..]

[..]考虑了函数内的局部变量,并将其包含在另一个早期建议中(由特殊内置控件控制local),但由于它们不适合为函数开发的简单模型,并且由于添加了一些反对意见而被删除另一个新的特殊内置功能,它不是历史惯例的一部分。如果此局部变量机制在本标准的未来版本中采用,则实现应保留标识符local(以及typesetKornShell中使用的标识符)。

(强调我的)


ash(从80年代后期开始)也基于ash,它是local那里最一致的接口之一(例如,与bash中严重损坏的接口相比),bash只是最近(4.4)借用了local -(用于本地范围选项)($-仅针对该变量实施ash样式作用域)。ksh和yash没有local(只有pdksh变体有local),而是有typeset(在ksh93中,typeset仅在使用ksh语法声明的函数中提供了本地(静态)范围)。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.