3.5 Shell 扩展(Sehll Expansions)

在扩展被分割成标记(token)之后,其执行于命令行中。可以执行以下类型的扩展:

扩展顺序是:大括号扩展;波浪号扩展、参数和变量扩展、算术扩展和命令替换(采用由左至右顺序执行完成);单词分割;和文件名扩展。

如果系统支持的话,还有另外一种扩展可用:进程替换(process substitution)。其执行与波浪号扩展、波浪号扩展、参数和变量扩展、算术扩展和命令替换在同一时间。

在这些扩展执行之后,将移除在原始单词中出现的引号字符,除非引号字符引用了其自身(引用移除)。

只有大括号扩展、单词分割和文件名扩展能够增加扩展的单词数量;其它扩展将单一单词扩展为单一单词。唯一的例外是“"$@"”和“$*”扩展(参见 3.4.2《特殊参数》),还有“$"{name[@]}"”和“${name[*]}”(参见 6.7《数组》)。

在所有扩展之后,才会执行引用移除(参见 3.5.9《引用移除》)。

3.5.1 大括号扩展(Brace Expansion)

大括号扩展是一种产生任意个字符串的机制。这种机制类似于文件名扩展(参见 3.5.8《文件名扩展》),但不会产生文件名。大括号扩展的样式格式是由一个可选的前缀,后跟着一对大括号,其中是一系列以逗号分开的字符串或序列表达式,最后由可选的后缀组成。前缀是附加到大括号里的每一个字符串的前面,后缀附加到生成的每一个字符串的后面,其扩展过程是从左到右进行的。

大括号表达式是可以进行嵌套的。扩展生成的每一个字符串的结果是未排序过的;使用的是从左到右的顺序。例如:

bash$ echo a{d,c,b}e
ade ace abe

序列表达式的格式是“{x..y[…incr]}”。这里的“x”和“y”是整数或单个字符,“incr”是可选的表示增量的整数。当用作整数时,表达式将“x”与“y”之间的所有整数(包括 x 和 y)扩展出来。在整数前加前缀“0”,会强制限定产生项的宽度。当在“x”或“y”前加“0”,shell 会试图在所有需要加“0”的产生项前加“0”,以达到和“x”或“y”的位数相同。当用作字符时,表达式扩展为“x”到“y”之间的字典字符(包括 x 和 y),默认语言区域为 C。注意,“x”和“y”必须是同一类型值。当增量整数出现时,其为每一生成项提供增量差异。根据情况,默认使用“1”或“-1”增量。

大括号扩展会在其它扩展之前执行,并且在结果中保留其它扩展中的特殊字符。它所产生的是纯文本的。Bash 不会对扩展上下文或大括号之间的文本进行任何的语法翻译。

一个正确格式的大括号扩展必须包括未被引起来的一对大括号,和至少一个未被引起来的逗号或一个有效的序列表达式。任何格式不正确的大括号扩展将不会产生任何扩展。

一个前大括号“{”或逗号“,”可以使用反斜线进转义,从而防止被认为是大括号扩展的一部分。为了防止与参数扩展相冲突,字符串“${”不会被认为是合格的大括号扩展,并且会在“}”出现之前抑制大括号扩展。

这种结构作为一种快捷方法,通常用于在产生公共前缀比较长的多个字符串的情况下使用,例如:

mkdir /usr/local/src/bash/{old,new,dist,bugs}

chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

3.5.2 波浪号扩展(Tilde Expansion)

如果一个单词是由未被引起来的波浪号“~”开头,直到第一个未被引起来的斜线/的所有字符(或如果没有斜线的话,则是所有字符)都会被认为是波浪号前缀。如果在波浪号前缀中没有被引起来的字符,则波浪号后面的字符被视为合理的登录名(login name)。如果这个登录名是空字符串,这个波浪号就会被 shell 变量“HOME”的值替换。如果 HOME 未设置,则执行 shell 的用户的家目录将作为代替。否则,波浪号前缀将使用指定的登录名关联的家目录进行替换。

如果波浪号前缀是“~+”,则使用 shell 变量“PWD”的值替换波浪号前缀。如果前缀是“~-”,则使用 shell 变量“OLDPWD”的值进行替换。

如果在波浪号前缀中跟随在波浪号后面的字符是一个数字 N,在其前面可选出现“+”或“-”,就像使用内建命令“dirs”(参见 6.8 章《目录堆栈》)时所跟随的参数一样,则使用目录堆栈中相应的元素替换波浪号前缀。如果前缀中除了波浪号,只由不带有“+”或“-”号的数字组成,则默认为使用了“+”号。

如果登录名是无效的,或扩展失败,则其中的单词不会有任何变化。

每一次变量赋值时会立即检查跟随在“:”或第一个“=”后面的未被引起来的波浪号前缀。在这种情况下,波浪号扩展同样会被执行。因此,可以使用带有波浪号的文件名对变量“PATH”、“MAILPATH”和“CDPATH”进行赋值,shell 会将扩展结果赋值到这些变量中去。

下面表格列出了 Bash 是如何对未被引起来的波浪号前缀进行转换的:

波浪号扩展转换
~$HOME 的值
~/foo$HOME/foo
~fred/foo用户 fred 家目录下的 foo 目录
~+/foo$PWD/foo
~-/foo${OLDPWD-’~-’}/foo
~N“dirs +N”所显示的字符串
~+N“dirs +N”所显示的字符串
~-N“dirs -N”所显示的字符串

当满足变量赋值条件的单词作为简单命令的参数出现时,Bash 同样会对其进行波浪号扩展。当在 POSIX 模式时,Bash 是不会这样做的,除非在使用声明命令时。

3.5.3 Shell 参数扩展(Shell Parameter Expansion)

参数扩展、命令替换以及算术扩展是由字符“$”的出现开始的。用于扩展的参数名或符号可以使用大括号括起来。大括号是可选的,但其出现的目的是确保紧跟着括号的字符扩展为变量,并将其解释为名称的一部分。

当使用大括号时,其匹配的结束符是第一个未被使用反斜线转义的,或其未出现在引起来的字符串中的“}”,也不能出现在内嵌的算术扩展、命令替换或参数扩展中。

参数扩展的基本格式是“${parameter}”。“parameter”的值是会被替换的。“parameter”是在 3.4 章《Shell 参数》所描述的 shell 参数或一个数组引用(参见《数组》的第 6.7 节)。当“parameter”是一个多于一位的位置参数时,或当其后跟随着一个不能解释为参数名一部分的字符时,大括号是必须出现的。

如果“parameter”的第一个字符是一个感叹号“!”,并且“parameter”不是名称引用(nameref)时,则其引入了一个“间接级别”。Bash 使用叹号后面的“parameter”扩展所形成的值作为新的“parameter”;这会接着再扩展,并且生成的新值用于接下来的扩展中,而不是使用最开始的“parameter”的扩展结果。这就被称为间接扩展(indirect expansion)。如果“parameter”是名称引用(nameref),则对“parameter”引用到的变量名进行扩展,而不是执行完整的间接扩展。间接扩展的例外是下面要讲到的关于${!prefix*}${!name[@]}的扩展。感叹号必须紧跟着左大括号出现才会引入间接扩展。

在下面的每一种情形中,word 可以是由波浪号扩展、参数扩展、命令替换和算术扩展产生。

当没有执行子字符串扩展时,使用下面描述的格式(如,“:-”等),Bash 会对参数进行未设置(unset)或空(null)测试。省略了冒号“:”会导致只对参数进行未设置测试。换一种说法,如果带有冒号,则操作符测试的是参数是否存在和其值是否为空两种;如果没有冒号,操作符只测试是否存在。

${parameter:-word}

如果“parameter”未被设置或为空,该参数扩展将替换为“*word*”的扩展。否则,将替换为“parameter”的值。

${parameter:=word}

如果“parameter”未被设置或为空,“word”的扩展将赋值给“parameter”。之后该参数扩展将替换为“parameter”的值。位置参数和特殊参数不能使用此方法进行赋值。

${parameter:?word}

如果“parameter”未被设置或为空,“word”的扩展(或如果“word”没有给出,则是一条消息)将写入标准报错和退出shell(如果shell不是处于交互模式)。否则,该参数扩展替换为“parameter”的值。

${parameter:+word}

如果“parameter”未被设置或为空,该参数扩展不进行任何替换,否则将替换为“word”的扩展。

{parameter:offset}

{parameter:offset:length}

该参数扩展参考为子字符串扩展。其扩展为从“offset”指定位置开始的“length”长度的“parameter”的字符值。如果“parameter”是“@”,一个由“@”或“*”为下标的索引数组,或关联数组名,则产生与下面所描述的不同结果。如果省略了“length”,则扩展出的子字符串是从“offset”位置开始直到“parameter”末尾位置的值。“length”和“offset”是算术表达式(参见6.5节《Shell算术运算》)。

如果“offset”计算出的数小于零,“offset”所指定的位置是从“parameter”值的末尾开始向前的偏移量。如果“length”计算出的数小于零,则其翻译为从“parameter”末尾开始向前的偏移量,而不是字符个数,并且扩展将生成从“offset”到“length”位置的子字符串。注意,负数的“offset”必须使用至少一个空格和前面的冒号分开,用于防止和“:-”扩展产生混淆。

下面一些例列举了参数和下标数组的子字符串扩展:

$ string=01234567890abcdefgh
$ echo ${string:7}
7890abcdefgh
$ echo ${string:7:0}
$ echo ${string:7:2}
78
$ echo ${string:7:-2}
7890abcdef
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:0}
$ echo ${string: -7:2}
bc
$ echo ${string: -7:-2}
bcdef
$ set -- 01234567890abcdefgh
$ echo ${1:7}
7890abcdefgh
$ echo ${1:7:0}
$ echo ${1:7:2}
78
$ echo ${1:7:-2}
7890abcdef
$ echo ${1: -7}
bcdefgh
$ echo ${1: -7:0}
$ echo ${1: -7:2}
bc
$ echo ${1: -7:-2}
bcdef
$ array[0]=01234567890abcdefgh
$ echo ${array[0]:7}
7890abcdefgh
$ echo ${array[0]:7:0}
$ echo ${array[0]:7:2}
78
$ echo ${array[0]:7:-2}
7890abcdef
$ echo ${array[0]: -7}
bcdefgh
$ echo ${array[0]: -7:0}
$ echo ${array[0]: -7:2}
bc
$ echo ${array[0]: -7:-2}
bcdef

如果“parameter”是“@”,所产生的结果是从“offset”开始的“length”长度的位置参数。一个负的“offset”是从大于位置参数一位的位置开始关联的,所以“offset”为“-1”时被计算为最后一个位置参数。如果“length”计算为一个负数,则会出现扩展错误。

下面的例子列举了使用位置参数的子字符串扩展:

$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:7}
7 8 9 0 a b c d e f g h
$ echo ${@:7:0}

$ echo ${@:7:2}
7 8
$ echo ${@:7:-2}
bash: -2: substring expression < 0
$ echo ${@: -7:2}
b c
$ echo ${@:0}
./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:0:2}
./bash 1
$ echo ${@: -7:0}

如果“parameter”是一个带有下标“@”或“*”的索引数组名,则产生的结果是从`${parameter[offset]}`位置开始的“length”长度的数组成员。负数的“offset”是从大于指定数组的最大索引一位位置开始关联的。如果“length”计算得出一个负数,则出现扩展错误。

下面这些例子说明了如何使用索引数组进行子字符串扩展:

$ array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h)
$ echo ${array[@]:7}
7 8 9 0 a b c d e f g h
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}

将子字符串扩展应用于关联数组将产生不可确定的结果。

子字符串索引是从零开始索引的,除非是用于位置参数,其默认索引才起始于1。如果“offset”是0,并且使用的是位置参数,`$0`则添加到这个列表的前面。

${!prefix*}

${!prefix@}

扩展为所有以“prefix”开头的变量名,变量之间使用特殊变量“IFS”的第一个字符作为分隔符。当在双引号内使用带有“@”的扩展时,每一个变量名扩展为一个单独的单词。

${!name[@]}

${!name[@]}

如果“name”是一个数组变量,则扩展为分配给这个“name”的数组索引(键)列表。如果“name”不是一个数组,并且其是已存在并不为空的变量,则扩展为0。当扩展出现在双引号内并且使用的是“@”,则每个键扩展为分开的单词。

${#parameter}

替换为“parameter”扩展出的值的字符长度。如果“parameter”是“\*”或“@”,则替换为位置参数的个数。如果“parameter”是带有下标“\*”或“@”的数组,则替换为数组元素个数。如果“parameter”是一个带有负数下标的数组时,数字则翻译为相对“parameter”最大索引多1,所以负数是从数组末尾向前的索引,即-1代表最后一个元素。

${parameter#word}

${parameter##word}

“word”扩展生成一个样式并且依照后面3.5.8.1节《样式匹配》中所描述的规则进行匹配。如果样式匹配到“parameter”扩展值的开头部分,扩展结果则是“parameter”值的样式最短(使用“#”)匹配或样式最长(使用“##”)匹配后未匹配的部分。如果“parameter”是“@”或“\*”,样式移除操作会轮流应用到每一个位置参数,并且扩展生成一个结果列表。如果“parameter”是一个带有下标“@”或“\*”的数组变量时,样式移除操作将轮流应用到数组的每一个元素上,并且扩展生成一个结果列表。

${parameter%word}

${parameter%%word}

“word”扩展生成一个样式并且依照后面3.5.8.1节《样式匹配》中所描述的规则进行匹配。如果样式匹配到“parameter”扩展值的末尾部分,扩展结果则是“parameter”值的样式最短(使用“%”)匹配或样式最长(使用“%%”)匹配后未匹配的部分。如果“parameter”是“@”或“*”,样式移除操作会轮流应用到每一个位置参数,并且扩展生成一个结果列表。如果“parameter”是一个带有下标“@”或“*”的数组变量时,样式移除操作将轮流应用到数组的每一个元素上,并且扩展生成一个结果列表。

${parameter/pattern/string}

“pattern”扩展生成一个类似于文名件扩展中的样式。“parameter”扩展后的值与样式“pattern”进行最长匹配,并使用“string”对其匹配进行替换。匹配执行规则请参考后面3.5.8.1节《样式匹配》。如果“pattern”是由“/”开头,所有的匹配都将使用“string”进行替换。一般情况下只对第一次匹配进行替换。如果“pattern”是以“#”开头,则样式只在“parameter”扩展值的开头进行匹配。如果“pattern”是以“%”开头,则样式只在“parameter”扩展值的末尾进行匹配。如果“string”是空的,所有与样式匹配到的将会被删除,并且“pattern”其后的“/”也可以省略。如果shell选项“nocasematch”(参见4.3.2节《内建命令shopt》对shopt的描述)开启,则匹配执行时将忽略字母字符的大小写。如果“parameter”是“@”或“\*”,则轮流对每一个位置参数应用替换操作,并且扩展为一个结果列表。如果“parameter”是一个下标为“@”或“\*”的数组,则轮流对数组中每一个元素进行替换操作,并生成一个结果列表。

${parameter^pattern}

${parameter^^pattern}

${parameter,pattern}

${parameter,,pattern}

这个扩展改写的是“parameter”里的字母字符的大小写。“pattern”扩展生成一个类似于文件名扩展中的样式。依据“pattern”对在扩展的“parameter”值中的每一个字符进行测试。如果匹配到了样式,则对大小写进行转换。样式不会试图进行多于一个字符的匹配。操作符“^”将匹配到样式的字符从小写改为大写;操作符“,”将匹配到的字符从大写改为小写。操作符“^^”和“,,”将改写扩展值中的每一个匹配的字符;“^”和“,”只对扩展值中第一个匹配到的字符进行改写。如果省略了“pattern”,它被视为使用了一个“?”,即匹配每一个字符。如果“parameter”是“@”或“\*”,则大小写的改写将轮流应用于每一个位置参数,并且生成一个结果列表。如果“parameter”是一个带有“@”或“\*”下标的数组变量,则大小写的改写将轮流应用于数组中的每一个元素,并生成一个结果列表。

${parameter@operator}

根据“operator”值的不同,这个扩展即可以用于“parameter”值的转换,又可以用于“parameter”它自身的信息显示。每个“operator”是一个单一的字符:

U
    扩展生成一个字符串,是将“parameter”的值中所有小写字母字符改写为大写。
u
    如果“parameter”值的第一个字符是字母的话,则将该字符改写为大写。
L
    扩展生成一个字符串,是将“parameter”的值中所有大写字母字符改写为小写。
Q
    扩展生成一个字符串,是将“parameter”的值引用为一种可再次用于输入的格式。
E
    扩展生成一个字符串,是将带有反斜线转义序列的“parameter”的值扩展为带有“$'...'”引用机制的值。
P
    扩展生成一个字符串,是将“parameter”的值生成为类似于提示符字符串(参见6.9《提示符控制》)。
A
    扩展生成一个赋值语句或“declare”命令格式的字符串。如果对其进行运算,将会使用该语句产生的属性和值对“parameter”进行重新创建。
K
    生成“parameter”值的可带引号版本。如果“parameter”是索引数组或关联数组(参见6.7《数组》),其会打印带引号的“键-值”对序列。
a
    扩展生成表示“parameter”属性的字符串。

如果“parameter”是“@”或“\*”,则操作轮流应用于每一个位置参数,并且扩展生成一个结果列表。如果“parameter”是一个带有“@”或“\*”下标的数组变量,则操作轮流应用于数组中每一个元素,并生成一个结果列表。

扩展结果可由下面所描述的单词分割和文件名扩展生成。

3.5.4 命令替换(Command Substitution)

命令替换允许使用命令的输出来替换命令本身。当命令使用下面格式包围起来时会出现命令替换:

$(command)

`command`

Bash 在子 shell 环境中运行“command”来执行这个扩展。并且使用“command”的标准输出来代替命令替换,并将尾部所有的换行删除。内嵌的换行是不会被删除的,但其可以在单词分割时进行删除。命令替换$(cat file)等同于$(< file),但执行速度快于后者。

当使用了老式的反引号“`”格式的命令替换,其中的反斜线则保留其字符意义,除非其后跟随着“$”、“`”或“\”。在开头的反引号后的第一个未前置反斜线的反引号代表命令替换结束。当使用“$(command)”格式时,所有在小括号之间的字符组成了命令;这里不会有特殊字符处理。

命令替换可以进行内嵌。当使用反引号进行内嵌时,要使用反斜线对内圈的反引号进行转义。

如果替换出现在双引号中,替换结果不会进行单词分割和文件名扩展。

3.5.5 算术扩展(Arithmetic Expansion)

算术扩展允许对算术表达式进行运算并进行结果替换。算术扩展的格式是:

$(( expression ))

表达式的处理就像其在双引号内一样,但小括号内的双引号不会被特殊处理。在表达式中所有的标记都可以是由参数和变量扩展、命令替换或引用移除生成。其处理结果被视为算术表达式进行运算。算术扩展是可以进行内嵌的。

依据 6.5 章节《Shell 算术运算》所描述的规则进行运算。如果表达式是无效的,Bash 则向标准报错打印一条失败消息,并且不会进行任何替换。

3.5.6 进程替换(Process Substitution)

进程替换允许使用文件名来引用为进程的输入或输出。其格式为:

<(list)

>(list)

进程“list”运行于异步模式,并且其输入或输出表现为一个文件名。这个文件名作为扩展结果以参数的形式传入当前命令。如果使用了“>(list)”格式,写入文件将为“list”提供输入。如果使用了“<(list)”格式,读取作为参数传递的文件将获得“list”的输出。注意,在“<”或“>”与后面的小括号之间是没有空格的,否则将解释为重定向。支持进程替换的系统也支持命名管道(FIFOs)或名为开放文件的“/dev/fd”方法。

当进程替换可用时,其可以和参数和变量扩展、命令替换和算术扩展同时执行。

3.5.7 单词分割(Word Splitting)

shell 会扫描没有出现在双引号内的参数扩展、命令替换及算术扩展的结果进行单词分割。

Shell 将“$IFS”中的每一个字符视为分隔符,并且使用这些字符作为字段终结符将其它扩展所产生的结果分割为多个单词。如果“IFS”未设置,或其值是正好是空格(space)、制表符(tab)或换行(newline),默认是这样的,则出现在前面扩展结果中开头和末尾的这三个符号的序列将被忽略,并且任何没有出现在开头和末尾的“IFS”字符序列将被用做分隔单词。如果“IFS”中有一个不同于默认值的值,并且有空白字符——空格、制表符和换行出现在 IFS 中,则出现在单词开头和末尾的这些空白字符序列将被忽略。任何出现在“IFS”中的非“IFS”空白字符,连同其相邻的 IFS 空白字符都用于字段分隔。一个 IFS 空白字符序列也被视为分隔符。如果 IFS 的值是空(null),则不会发生单词分割。

保留显式空(null)参数(""'')作为空(empty)字符串传递给命令。从参数扩展中得到的无值的,未使用引号引用的隐式空(null)参数将会被移除。如果在双引号中无值参数进行扩展生成空(null)参数,会将其保留并作为空(empty)字符串传递给命令。当一个被引起来的空参数作为单词的一部分出现时并且单词扩展的值是非空的,则空参数被移除。就是说,单词“-d''”在单词分割和空参数移除后会变成“-d”。

注意,如果没有出现扩展,则不会进行单词分割。

3.5.8 文件名扩展(Filename Expansion)

在单词分割后,除非设置了“-f”选项(参见 4.3.1《内建命令 set》),Bash 会在每一个单词中扫描字符“*”、“?”和“[”。如果其中某个字符出现了,并且其未被引号括起来,则这个单词就被当作样式,并且替换为与该样式匹配的按字母顺序排序的文件名列表。如果没有找到匹配的文件名,并且 shell 选项“nullglob”没有开启,则单词不会有任何变化。如果设置了“nullglob”选项,并且没有找到任何匹配,则移除该单词。如果 shell 选项“failglob”开启,并且没有找到任何匹配,则打印一条出错消息并且不会执行该命令。如果开启了 shell 选项“nocaseglob”,则执行的匹配操作会忽略字母的大小写。

当一个样式用于文件名扩展时,文件名开头的或紧跟一个斜线的字符点“.”必须进行显式匹配,除非设置了 shell 选项“dotglob”。文件名“.”和“..”必须总是进行显式匹配,即使设置了“dotglob”。在其它情况下,字符“.”是不会被特殊处理的。

当匹配文件名时,斜线必须始终在样式中使用斜线进行显式匹配,但在其它匹配上下文中,其可以使用下面描述(3.5.8.1《样式匹配》)的特殊样式字符进行匹配。

可参见 4.3.2《内建命令 shopt》中的对 shopt 中的选项“nocaseglob”、“nullglob”、“failglob”和“dotglob”的相关描述。

shell 变量“GLOBIGNORE”可用于限制匹配到样式的文件名集合。如果设置了“GLOBIGNORE”,每一个匹配到的文件名并且其也匹配到“GLOBIGNORE”中的一个样式,则会从匹配结果列表中移除。如果设置了“nocaseglob”选项,则不在“GLOBIGNORE”中的样式匹配则忽略大小写。当“GLOBIGNORE”设置了并且不为空,文件名“.”和“..”总是会被忽略的。然而,将“GLOBIGNORE”设置为非空值时,会具有开启“dotglob”选项的效果,因此所有以“.”开头的其它文件名都将会匹配到。为了能得到像之前忽略以“.”开头的文件名的行为,将“.*”这个样式加入到“GLOBIGNORE”中去。当“GLOBIGNORE”被释放后,选项“dotglob”会被关闭。

3.5.8.1 样式匹配(Pattern Matching)

除了下面所提到的特殊字符,其它出现在样式的任意字符都匹配到其自身。“NUL”空字符不能出现在样式中。反斜线会将其后跟随的字符进行转义;转义符号反斜线会在匹配时被丢弃。如果特殊样式字符进行原字符匹配,就必须使用引用进行转义。

下面是特殊样式字符的含义:

特殊样式字符含义
*匹配任意字符串,包括空(null)字符串。当 shell 选项“globstar”开启了,并且“”使用在文件名扩展的上下文中,两个相邻的“”视为一个单一的样式,其将会匹配所有文件和零个或多个目录及子目录。如果其后跟随一个斜线“/”,则两个相邻的“*”只匹配目录或子目录。
?匹配任意一个字符。
[…]匹配任意一个在括号中的字符。使用中横线分隔的一对字符表示为范围表达式;其可匹配到落于这两个字符之间的任意字符,包括这两个字符。字符顺序使用的是当前语言区域字符排序序列集。如果跟随着“[”的第一个字符是“!”或“^”,则匹配到的是这个括号未包含的字符。要匹配横线“-”,可将其置于括号中字符集的第一个或最后一个字符的位置。在字符集中可将“]”置于第一个字符位置对其进行匹配。如果设置了当前语言区域和 shell 变量“LCCOLLATE”和“LC_ALL”的值,在范围表达式中的字符排序顺序可由它们决定。
例如,在默认的 C 语言区域中“[a-dx-z]”等同于“[abcdxyz]”。许多语言区域按字典顺序排序字符,并且在这些语言区域中“[a-dx-z]”通常不等同于“[abcdxyz]”;例如,它可能等同于“[aBbCcDdxXyYz]”。为了在中括号表达式中获得范围的传统翻译,你可以设置环境变量“LC_COLLATE”或“LC_ALL”的值为“C”或开启 shell 选项“globasciiranges”将语言区域强制设置为“C”。
在“[”和“]”内部,可以使用语法“[:class:]”来指定下面这些定义在 POSIX 标准中的字符类:
alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit
字符类可匹配该类中的任意字符。“word”字符类可匹配字母、数字和下划线“
”。
在“[”和“]”内部,可以使用语法[=c=]来指定等同类,其匹配像字符“c”的具有相同校对权重的所有字符(定义为当前语言区域的)。
在“[”和“]”内部,可以使用语法[.symbol.]来匹配校对符号“symbol”。

如果使用内建命令“shopt”开启了“extglob”选项,则一些扩展样式匹配操作符就可以使用了。在下面的描述中,“pattern-list”是一个由“|”作为分隔符的多个样式列表。复合样式可以由下列一个或多个子样式构成:

扩展样式操作符描述
?(pattern-list)匹配给定样式零次或一次。
*(*pattern-list*)匹配给定样式零次或多次。
+(pattern-list)匹配给定样式一次或多次。
@(pattern-list)匹配给定样式一次。
!(pattern-list)匹配给定样式外的任意样式。

对于长字符串的复杂扩展样式的匹配速度是比较慢的,特别是当样式包含交替并且字符串包含多个匹配。可将复杂匹配替换为针对多个短字符串的匹配,或可以将单个长字符串替换为字符串数组来加快速度。

3.5.9 引用移除(Quote Removal)

在前面的扩展完成之后,所有未从前面扩展结果产生的未被引起来的字符“\”、“‘”和““”都要被移除。