6.12 shell的兼容模式
Bash-4.0引入了shell兼容性级别的概念,它被指定为shopt内置函数的一组选项(compat31
、compat32
、compat40
、compat41
,等等)。 目前只有一个兼容性级别 – 每个选项都是互斥的。 兼容性级别旨在允许用户在迁移脚本以使用当前功能和行为时,选择与新版本不兼容的以前版本的行为。它旨在成为一个临时的解决方案。
本节没有提到对某一特定版本来说是标准的行为(例如,设置compat32
意味着引用regexp匹配运算符的rhs会引用单词中的特殊regexp字符,这是bash-3.2和后续版本中的默认行为)。
如果用户启用了,比如说,compat32
,它可能会影响到其他兼容性级别的行为,直到并包括当前的兼容性级别。 这个想法是,每个兼容性级别控制的行为在该版本的Bash中发生了变化,但该行为可能在早期版本中就存在了。 例如,使用基于本地的比较的[[
命令的变化是在bash-4.1中发生的,而早期版本使用的是基于ASCII的比较,所以启用compat32
也会启用基于ASCII的比较。而早期版本使用的是基于ASCII的比较,所以启用compat32
也会启用基于ASCII的比较。 这种细化程度可能不足以满足所有的使用,因此用户应该谨慎地使用兼容性级别。 阅读特定功能的文档以了解当前行为。
Bash-4.3 引入了一个新的 shell 变量:BASH_COMPAT
。分配给此变量的值(十进制版本号,如 4.2,或对应于 compat
NN选项的整数,如42)决定了兼容性级别。
从bash-4.4开始,Bash已经开始弃用旧的兼容级别。 最终,这些选项将被移除,转而使用BASH_COMPAT
。
Bash-5.0是最后一个版本,在这个版本中会有一个单独的shopt选项,用于以前的版本。用户应该在bash-5.0及以后的版本中使用BASH_COMPAT
。
下表描述了每个兼容性级别设置所控制的行为变化。 compat
NN标签是作为使用以下机制之一将兼容性级别设置为NN的缩写。 对于bash-5.0之前的版本,可以使用相应的compat
NN shopt选项来设置兼容性级别。 对于bash-4.3及以后的版本,BASH_COMPAT
变量是首选,而对于bash-5.1及以后的版本,它是必须要有的。
compat31
- 引用
[[
命令的正则表达式匹配操作符(=~) 的 rhs 没有特殊效果。
- 引用
compat32
- 中断一个命令列表,如"a; b; c",会导致执行列表中的下一条命令(在bash-4.0及以后的版本中,shell的行为就像它收到中断一样,所以中断列表中的一条命令会中止整个列表的执行)。
compat40
[[
命令的‘<’和‘>’操作符在比较字符串时不考虑当前的语言环境;它们使用ASCII排序。 bash-4.1之前的Bash版本使用ASCII排序和strcmp(3);bash-4.1及以后的版本使用当前语言环境的排序和strcoll(3)。
compat41
- 在posix模式下,
time
后面可以跟上选项,并且仍然被识别为一个保留字(这是POSIX解释267)。 - 在posix模式下,解析器要求在双引号${…}参数扩展的word部分出现偶数个单引号,并对其进行特殊处理,因此单引号内的字符被认为是有引号的(这是POSIX解释221)。
- 在posix模式下,
compat42
- 在双引号模式替换中,替换的字符串不会被去除引号,因为在bash-4.2之后的版本中,它是这样做的
- 在posix模式下,当扩展双引号${…}参数的word部分时,单引号被认为是特殊的,可以用来引用结尾括号或其他特殊字符(这是POSIX解释221的一部分);在以后的版本中,单引号在双引号单词扩展中不是特殊的。
compat43
- 如果试图使用带引号的复合赋值作为声明的参数,shell不会打印警告信息(例如,声明-a foo=’(1 2)’)。后来的版本警告说这种用法已经过时了
- 扩词错误被认为是导致当前命令失败的非致命错误,即使在posix模式下也是如此(默认的行为是使它们成为导致shell退出的致命错误)。
- 当执行一个shell函数时, 循环状态(while/until/等)不会重置, 所以该函数中的
break
或continue
会破坏或继续调用环境中的循环。Bash-4.4和更高版本重置了循环状态以防止这种情况的发生
compat44
- shell设置了
BASH_ARGV
和BASH_ARGC
所使用的值,所以即使没有启用扩展调试模式,它们也可以扩展到shell’的位置参数。 - 子shell从它的父环境中继承循环,所以
break
或continue
将导致子shell退出。 Bash-5.0及以后的版本会重置循环状态,以防止退出。 - 即使shell不在posix模式下,像
export
和readonly
这样设置属性的内置程序前面的变量赋值也会继续影响调用环境中的同名变量。
- shell设置了
compat50 (set using BASH_COMPAT)
- Bash-5.1改变了
$RANDOM
的生成方式,引入了稍多的随机性。如果shell的兼容性级别设置为50或更低,它就会恢复到bash-5.0和以前版本的方法,所以通过给RANDOM
赋值来给随机数发生器播种会产生与bash-5.0中相同的序列 - 如果命令哈希表是空的,在bash-5.1之前的Bash版本会打印一条信息,即使是在产生可以作为输入使用的输出时也是如此。Bash-5.1在提供-l选项时抑制了该信息。
- Bash-5.1改变了
compat51 (set using BASH_COMPAT)
unset
内置函数将根据给定的参数(如'a[@]')取消设置数组。Bash-5.2 将取消设置带有键“@”的元素(关联数组)或删除所有元素而不取消设置数组(索引数组)。- 算术命令((...))和算术for语句中的表达式可以扩展一次以上。
- 在
[[
条件命令中作为算术运算符的参数的表达式可以被多次展开。 - 在子串参数括号扩展中的表达式可以被扩展一次以上
- 在$((......))词的扩展中的表达式可以被扩展一次以上
- 用作索引数组下标的算术表达式可以被多次展开
test -v
,当给出一个‘A[@]’的参数时,其中A是一个现有的关联数组,如果数组有任何集合元素,将返回true。 Bash-5.2将寻找并报告一个名为‘@’的键。- ${parameter[:]=value}词的扩展将返回value,在任何特定变量的转换被执行之前(例如,转换为小写)。Bash-5.2将返回分配给该变量的最终值。
- 解析命令替换将表现得好像启用了扩展 glob(见2 Shopt 内置程序),因此解析包含extglob模式的命令替换(例如,作为shell函数的一部分)的命令替换不会失败。这假定意图是在执行命令和执行单词扩展之前启用 extglob。 如果在执行命令时 extglob 尚未启用,它将在单词扩展时失败。