3.5 Shell的扩展
扩展是在命令行被分割成token
后进行的。有七种扩展方式可供执行:
- 大括号扩展
- 波浪号的扩展
- 参数和变量扩展
- 命令替换
- 算术扩展
- 分词
- 文件名扩展
扩展的顺序是:大括号扩展,倾斜符号扩展,参数和变量扩展,算术扩展和命令替换(以从左到右的方式进行),单词拆分,以及文件名扩展。
在可以支持它的系统上,有一个额外的扩展可用:进程替换。 这是波浪号、参数、变量,算术扩展和命令替换同时执行。
在进行这些扩展后,存在于原词中的引号字符将被删除,除非它们本身已被引号(引号删除)。
只有大括号扩展、分词和文件名扩展可以增加扩展的字数,其他的扩展都是将一个字扩展为一个字。 唯一的例外是"$@"
和$*
的扩展(见2 特殊参数),以及"${name[@]}"
和${name[*]}
(见6.7 数组)的扩展。
在所有的扩展之后,quote removal
(见9 引用删除)被执行。
1 大括号扩展
大括号扩展是一种可以生成任意字符串的机制。 这种机制类似于文件名扩展(见8 文件名扩展),但生成的文件名不需要存在。要进行大括号扩展的模式采取了可选的preamble的形式,后面是一系列逗号分隔的字符串或一对大括号之间的序列表达式,后面是可选的postscript。 前言是以大括号内包含的每个字符串为前缀,然后将postscript附加到每个产生的字符串上,从左到右扩展。
方括号扩展可以嵌套。 每个扩展的字符串的结果不进行排序;从左到右的顺序被保留。 例如:。
bash$ echo a{d,c,b}e
ade ace abe
序列表达式的形式是{x..y[..incr]}
,其中x和y是整数或字母,而incr是一个可选的增量,是一个整数。 当提供整数时,表达式扩展到x和y之间的每个数字,包括在内。 提供的整数可以以‘0’为前缀,强制每个项具有相同的宽度。当x或y以0开头时,shell会尝试强制所有生成的术语包含相同数量的数字,必要时进行零填充。当提供字母时,表达式会使用默认的C语言扩展到x和y之间的每个字符。 注意x和y必须是相同的类型(整数或字母)。 当提供增量时,它被用作每个项之间的差异。默认的增量是1或-1,视情况而定。
Brace扩展是在任何其他扩展之前进行的,并且在结果中保留了其他扩展的任何特殊字符。它是严格的文本性的。Bash不会对扩展的上下文或大括号之间的文本进行任何句法解释。
一个正确的括号扩展必须包含无引号的开括号和闭括号,以及至少一个无引号的逗号或一个有效的序列表达式。 任何不正确的括号扩展都不会被改变。
{或‘,’可以用反斜杠引证,以防止其被视为括号表达式的一部分。 为了避免与参数扩展冲突,字符串‘${’不被视为有资格进行括号扩展,并抑制括号扩展,直到最后的‘}’为止。
当要生成的字符串的共同前缀比上面的例子长时,这种结构通常被用作速记。
mkdir /usr/local/src/bash/{old,new,dist,bugs}
或
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
2 波浪号扩展
如果一个词以未加引号的波浪字符(‘~’)开始,则直到第一个未加引号的斜杠(或者所有字符,如果没有未加引号的斜线)的所有字符都被视为波浪前缀。 如果波浪号前缀中的任何字符都未被引用,波浪号后的波浪号前缀中的字符将被视为可能的登录名。如果这个登录名是空字符串,波浪号将被替换为HOME
shell变量的值。 如果HOME
没有设置,执行shell的用户的主目录将被替换。 否则,tild-prefix将被替换为与指定登录名相关的主目录。
如果波浪号前缀是‘~+’,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也会对满足变量赋值条件的词(见3.4 shell参数)进行波浪号扩展,当它们作为简单命令的参数出现时,Bash不会这样做,除了上面列出的声明命令,当处于POSIX模式时,Bash不会这样做。
3 Shell参数扩展
‘$’字符引入了参数扩展、命令替换或算术扩展。要扩展的参数名或符号可以用大括号括起来,大括号是可选的,但其作用是保护要扩展的变量不受紧随其后的字符影响,这些字符可能被解释为名称的一部分。
当使用大括号时,匹配的结尾大括号是第一个‘}’,没有被反斜杠转义或在一个引号字符串中,也没有在一个嵌入式算术扩展、命令替换或参数扩展中。
参数扩展的基本形式是${parameter}。参数的值被替换。parameter是上文所述的shell参数(见3.4 shell参数)或数组引用(见6.7 数组)。当parameter是一个数字以上的位置参数,或者当parameter后面有一个不被解释为其名称一部分的字符,则需要加大括号。
如果参数的第一个字符是感叹号(!),并且 parameter 不是 nameref,它引入了一个间接级别。Bash 使用通过扩展其余部分形成的值作为新的parameter;然后将其扩展,该值将用于扩展的其余部分,而不是原始parameter的扩展,这称为indirect expansion
。该值受波浪号扩展、参数扩展、命令替换和算术扩展的影响。如果 parameter 是一个 nameref,这将扩展为parameter 引用的变量而不是执行完全的间接扩展。例外情况是下面所描述的${!prefix*} 的扩展和 ${!name[@]}。感叹号必须紧跟在左大括号之后,以引入间接性。
在下面的每一种情况下,word都会受到波浪号扩展、参数扩展、命令替换和算术扩展的影响。
当不执行子串扩展时,使用下面描述的形式(例如,‘:-’),Bash测试未设置或空的参数。 省略冒号的结果是只测试未设置的参数。 换句话说,如果包含冒号,操作者既测试parameter的存在,又测试其值是否为空;如果省略冒号,操作者只测试其存在。
${parameter:-word}
如果参数未设置或为空,则替换字的扩展。否则,就用参数的值来替代。
$ v=123 $ echo ${v-unset} 123
${parameter:=word}
如果parameter未设置或为空,word的扩展被分配给parameter,然后parameter的值被替换。位置参数和特殊参数不能以这种方式分配。
$ var= $ : ${var:=DEFAULT} $ echo $var DEFAULT
${parameter:?word}
如果参数为空或未设置, word 的扩展值(如果 word 不存在,则会有相应的信息)被写入标准错误,如果shell不是交互式的,则退出。否则,参数的值被替换。
$ var= $ : ${var:?var is unset or null} bash: var: var is unset or null
${parameter:+word}
如果参数为空或未设置,则不进行任何替换,否则将替换word的扩展。
$ var=123 $ echo ${var:+var is set and not null} var is set and not null
${parameter:offset}
${parameter:offset:length}
这被称为子串扩展。 它从offset指定的字符开始,最多扩展到参数的值的length字符。如果parameter是‘’或‘*’,一个以‘’或‘*’为下标的索引数组,或一个关联数组名称,结果会有所不同,如下所述。如果省略了length,它将扩展为parameter的值的子串,从offset指定的字符开始,延伸到该值的末端。length和offset是算术表达式(见6.5 shell算术)。
如果offset评估为一个小于0的数字,则该值被用作从parameter值的末尾开始的字符偏移。 如果length评估为一个小于0的数字,则它被解释为从parameter值的末尾开始的字符偏移,而不是一个字符数,扩展为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
如果参数是‘’或‘*’,结果是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[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}
对一个关联数组进行子串扩展会产生未定义的结果。
子串索引是基于0的,除非使用了位置参数,在这种情况下,索引默认从1开始。 如果offset是0,并且使用了位置参数,那么
$0
就会在列表前加上前缀。${!prefix*}
${!prefix@}
扩展到名称以前缀开头的变量名称,并以
IFS
特殊变量的第一个字符分开。 当使用‘@’并且扩展出现在双引号内时,每个变量名称都会扩展到一个单独的单词。${!name[@]}
${!name[*]}
如果name是一个数组变量,则扩展到name中分配的数组索引(key)列表。 如果name不是一个数组,如果name被设置,则扩展到0,否则为空。 当‘@’被使用并且扩展出现在双引号内,每个key扩展到一个单独的单词。
${#parameter}
替换parameter扩展值的字符长度。如果 parameter 是‘*’或‘@’,则替换的值是位置参数的数量。如果parameter是以'*'或'@'为下标的数组名,则替换的值为数组中元素的数量。如果parameter是下标为负数的索引数组名称,则该数字被解释为相对于大于parameter最大索引的一个,因此负索引从数组末尾开始倒计时,索引 -1 引用最后一个元素。
${parameter#word}
${parameter##word}
对 word 进行扩展,产生一个模式,并根据下面描述的规则进行匹配(见8.1 模式匹配)。如果该模式与参数的扩展值的开头相匹配,那么扩展的结果就是parameter的扩展值,并删除最短的匹配模式(‘#’情况)或最长的匹配模式(‘##’情况)。如果parameter是‘’或‘*’,则依次对每个位置参数进行模式删除操作,展开后就是结果列表。如果parameter是以‘’或‘*’为下标的数组变量,则依次对数组中的每个成员进行模式去除操作,扩展后的结果是列表。
${parameter%word}
${parameter%%word}
word 被扩展以产生一个模式,并根据下面描述的规则进行匹配(见8.1 模式匹配)。如果该模式与参数的扩展值的尾部相匹配,那么扩展的结果就是parameter的值,并删除最短的匹配模式(‘%’情况)或最长的匹配模式(‘%%’情况)。如果parameter是‘’或‘*’,则依次对每个位置参数进行模式删除操作,展开后就是结果列表。如果parameter是以‘’或‘*’为下标的数组变量,则依次对数组中的每个成员进行模式去除操作,扩展后的结果是列表。
${parameter/pattern/string}
${parameter//pattern/string}
${parameter/#pattern/string}
${parameter/%pattern/string}
pattern就像在文件名扩展中一样被扩展以产生模式。Parameter被扩展,pattern对其值的最长匹配被替换为string。string经历了波浪号扩展、参数和变量扩展、算术扩展、命令和进程替换以及引号删除。 匹配根据下面描述的规则进行(见8.1 模式匹配)。
如果parameter和pattern之间有两个斜杠(上述第二种形式),那么模式的所有匹配将被替换为字符串。 如果pattern前面有‘#’(上述第三种形式),它必须在参数的扩展值的开头匹配。如果pattern前面是‘%’(上面的第四种形式),它必须在parameter的扩展值的末端匹配。如果string的扩展值为空,则删除pattern的匹配;如果string为空,则删除pattern的匹配,并且pattern之后的‘/’可以省略。
如果使用
patsub_replacement
shell选项启用了shopt
,那么string中任何未加引号的‘&’实例都会被替换成pattern的匹配部分。 这是为了重复一个常见的sed
成语。引用string的任何部分都会禁止在被引部分的扩展中进行替换,包括存储在shell变量中的替换字符串。 反斜线将转义‘&’在string中;反斜线被移除,以允许在替换字符串中出现字面的‘&’。如果string是双引号,用户应该注意避免反斜杠和双引号之间不必要的互动,因为反斜杠在双引号中具有特殊含义。模式替换在扩展string之后,会对未加引号的‘&’进行检查,因此用户应确保在替换中正确引用任何他们希望从字面上理解的‘&’的出现,并确保任何他们希望被替换的‘&’ 的实例未加引号。
比如说。
var=abcdef rep='& ' echo ${var/abc/& } echo "${var/abc/& }" echo ${var/abc/$rep} echo "${var/abc/$rep}"
将会显示四行"abc def",而
var=abcdef rep='& ' echo ${var/abc/\& } echo "${var/abc/\& }" echo ${var/abc/"& "} echo ${var/abc/"$rep"}
与模式移除操作符一样,替换字符串周围的双引号引用了扩展的字符,而整个参数替换周围的双引号则没有,因为扩展是在一个不考虑任何周围双引号的情况下进行的。
由于反斜线可以转义‘&’,它也可以转义替换字符串中的反斜线。 这意味着‘\’将在替换中插入一个字面的反斜线,所以这两条
echo
命令var=abcdef rep='\\&xyz' echo ${var/abc/\\&xyz} echo ${var/abc/$rep}
将同时输出‘\abcxyzdef’。
应该很少有必要只用双引号来括住string。
如果
nocasematch
shell选项(见2 Shopt 内置程序中对shopt
的描述)被启用,则进行匹配时不考虑字母字符的大小写。 如果参数是‘@’或‘*’,替换操作将依次应用于每个位置参数,并且扩展为结果列表。如果parameter是以‘’或‘*’为下标的数组变量,则依次对数组中的每个成员进行替换操作,扩展后的结果是列表。${parameter^pattern}
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}
这种扩展修改了parameter中的字母字符的大小写。 pattern被扩展以产生一个模式,就像在文件名扩展中一样。 parameter的扩展值中的每个字符都与pattern进行测试,如果它与模式匹配,其大小写将被转换。 该模式不应试图匹配一个以上的字符。
‘^’运算符将匹配pattern的小写字母转换为大写字母;‘,’运算符将匹配的大写字母转换为小写。‘^^’和‘,,’扩展项将扩展值中的每个匹配字符进行转换;‘^’和‘,’扩展项只匹配并转换扩展值中的第一个字符。如果pattern被省略,它将被视为‘?’,即匹配每个字符。
如果parameter是‘@’或‘*’,则依次对每个位置参数进行case修改操作,扩展后的结果是列表。如果parameter是以‘’或‘*’为下标的数组变量,则依次对数组中的每个成员进行case修改操作,扩展后的结果是列表。
${parameter@operator}
扩展要么是parameter的值的转换,要么是关于parameter本身的信息,取决于operator的值,每个operator是一个字母:
U
扩展是一个字符串,它是parameter的值,小写字母字符被转换成大写字母。
u
扩展是一个字符串,它是parameter的值,如果是字母的话,第一个字符被转换为大写字母。
L
扩展是一个字符串,它是parameter的值,大写字母字符被转换为小写字母。
Q
扩展是一个字符串,它是parameter的值,以一种可以重复使用的格式引出,作为输入。
E
扩展是一个字符串,它是parameter的值,反斜杠转义序列的扩展与
$'…'
引号机制一样。P
扩展是一个字符串,它是将parameter的值扩展为提示字符串的结果(见6.9 控制提示符)。
A
扩展是一个赋值语句或
declare
命令形式的字符串,如果被评估,将重新创建parameter及其属性和值。K
产生parameter的可能引号版本的值,只是它将索引数组和关联数组的值打印成一串引号的键值对(见6.7 数组)。
a
该扩展是一个由代表parameter’属性的标志值组成的字符串。
k
就像‘K’转换一样,但在分词后将索引数组和关联数组的键和值扩展为独立的字。
如果参数是‘@’或‘*’,则依次对每个位置参数进行操作,扩展后的结果是列表。如果参数是以‘’或‘*’为下标的数组变量,则该操作依次应用于数组的每个成员,扩展后的结果是列表。
扩增的结果要进行字数分割和文件名扩增,如下文所述。
4 命令替换
命令替换允许命令的输出替代命令本身。 命令替换发生在一个命令被括起来的时候,如下图所示。
$(command)
或
`command`
Bash通过在子shell环境中执行command来执行扩展,并且用命令的标准输出来替换命令替换,同时删除任何尾部的新行。 嵌入的新行不会被删除,但在分词过程中可能会被删除。 命令替换$(cat file)
可以被等价但更快的$(< file)
所替换。
当使用旧式反引号形式的替换时,反斜杠保留其字面意义,除非后面是‘$’、‘`’或‘’。当使用$(command)
形式时,括号内的所有字符都构成了命令,没有一个字符被特别处理。
命令替换可以是嵌套的。在使用反引号形式时要嵌套,用反斜线转义内部反引号。
如果替换出现在双引号内,则不会对结果进行单词分割和文件名扩展。
5 算术扩展
算术扩展允许对一个算术表达式进行评估,并对其结果进行替换。算术扩展的格式是:
$(( expression ))
expression经历了与双引号内相同的扩展,但是expression中的双引号字符不会被特别处理并被移除。 表达式中的所有标记都经历了参数和变量扩展、命令替换和引号移除。 结果被视为要评估的算术表达式。 算术扩展可以被嵌套。
评估是根据下面列出的规则进行的(见6.5 shell算术)。 如果表达式无效,Bash会在标准错误中打印出一条表示失败的信息,并且不会发生替换。
6 进程替换
进程替换允许使用一个文件名来引用一个进程的输入或输出。 它的形式如下
<(list)
或
>(list)
进程list是异步运行的,它的输入或输出显示为一个文件名。 这个文件名作为扩展的结果被传递给当前命令的参数。 如果使用>(list)
形式,向文件的写入将为list提供输入。如果使用<(list)
形式,作为参数传递的文件应该被读取,以获得list的输出。 注意,在<
或>
和左括号之间不能出现空格,否则该结构将被解释为重定向。 在支持命名管道(FIFOs)或/dev/fd方法命名开放文件的系统上支持进程替换。
当有条件时,进程置换与参数和变量扩展、命令置换和算术扩展同时进行。
7 分词
shell扫描了参数扩展、命令替换和算术扩展的结果,这些结果没有发生在双引号内,以便进行分词处理。
shell将$IFS
的每个字符视为分隔符,并使用这些字符作为字段终止符将其他扩展的结果分割成字。 如果IFS
没有设置,或者它的值正好是<space><tab><newline>
,即默认值,那么位于前面扩展结果的开头和结尾的 <space>
、<tab>
和<newline>
序列被忽略,任何不在开头或结尾的IFS
字符序列都用于分隔字。如果IFS
的值不是默认值,那么在词的开头和结尾的空白字符space
、tab
和newline
的序列被忽略,只要空白字符在IFS
的值中(一个IFS
的空白字符)。 IFS
中任何不是IFS
的空白字符,连同任何相邻的IFS
的空白字符,限定一个字段。一串IFS
空白字符也被视为定界符。 如果IFS
的值为空,则不会发生分词。
明确的空参数(""
或''
)被保留下来,并作为空字符串传递给命令。 没有引号的隐式空参数,由没有值的参数扩展而来,被删除。 如果一个没有值的参数在双引号内被扩展,会产生一个空参数,并被保留下来,作为空字符串传递给命令。 当一个引号的空参数作为一个单词的一部分出现,而这个单词的扩展是非空的,空参数被删除。 也就是说,单词-d''
在分词和空参数删除后变成了-d
。
请注意,如果没有发生扩展,就不会进行分割。
8 文件名扩展
在分词之后,除非设置了-f选项(参见1 Set 内置程序),否则Bash会扫描每个词,以寻找‘*’、‘?’和‘[’等字符。如果这些字符之一出现,并且没有引号,那么这个词将被视为模式,并被替换为按字母排序的匹配模式的文件名列表(见8.1 模式匹配)。如果没有找到匹配的文件名,并且禁用了shell选项nullglob
,那么该词将保持不变。 如果设置了nullglob
选项,并且没有找到匹配的文件名,那么该词将被删除。 如果设置了failglob
shell选项,并且没有找到匹配的文件名,那么将打印一条错误信息,并且不执行该命令。 如果启用了shell选项nocaseglob
,那么进行匹配时将不考虑字母字符的大小写。
当模式用于文件名扩展时,文件名开头或斜杠后面的字符‘.’必须显式匹配,除非设置了 shell 选项 dotglob。为了匹配文件名“.”和“..”,模式必须以“.”开头(例如,“.?”),即使设置了dotglob
。如果启用了globskipdots
shell 选项,
文件名‘.’ 和 ‘..’ 永远不会匹配,即使模式以“.”开头。当不匹配文件名时,‘.’字符不会被特殊对待。
当匹配文件名时,斜线字符必须总是由模式中的斜线明确匹配,但在其他匹配情况下,它可以由一个特殊的模式字符匹配,如下所述(见模式匹配)。
参见2 Shopt 内置程序中对shopt
的描述,以了解对nocaseglob
、nullglob
、globskipdots
、failglob
和dotglob
等选项的描述。
GLOBIGNORE
shell变量可以用来限制匹配模式的文件名集合。如果设置了GLOBIGNORE
,每一个与GLOBIGNORE
中的模式相匹配的文件名都会从匹配列表中删除。 如果设置了nocaseglob
选项,对GLOBIGNORE
中的模式进行匹配时不考虑大小写。 当GLOBIGNORE
被设置且不为空时,文件名.和..总是被忽略。然而,将GLOBIGNORE
设置为非空值具有启用dotglob
壳选项的效果,因此所有其他以‘.’开头的文件名将被匹配。 要获得忽略以‘.’开头的文件名的旧行为,请将‘.*’作为GLOBIGNORE
中的模式之一。 当GLOBIGNORE
未设置时,dotglob
选项被禁止。
8.1 模式匹配
除了下面描述的特殊模式字符外,任何出现在模式中的字符都会与自己匹配。 NUL字符不能出现在模式中。 反斜杠可以转义后面的字符;在匹配时,转义的反斜杠会被丢弃。 如果要按字面意思匹配,特殊模式字符必须被引号化。
特殊模式的字符有以下含义。
*
匹配任何字符串,包括空字符串。 当
globstar
shell选项被启用,并且‘*’被用于文件名扩展上下文时,两个相邻的‘*’作为单个模式使用将匹配所有文件和零个或多个目录和子目录。如果后面有一个‘/’,两个相邻的‘*’将只匹配目录和子目录。?
匹配任何一个单一的字符。
[…]
匹配任何一个被包围的字符。一对用连字符隔开的字符表示一个范围表达式;在这两个字符之间的任何字符(包括在内),使用当前地区的排序和字符集,都被匹配。如果‘[’后的第一个字符是‘!’或‘^’,那么任何未被包围的字符都被匹配。A ‘-’可以通过将其作为集合中的第一个或最后一个字符进行匹配。A ‘]’可以通过将其作为集合中的第一个字符进行匹配。 范围表达式中字符的排序顺序以及范围中包含的字符由当前的locale以及
LC_COLLATE
和LC_ALL
shell变量的值(如果设置)决定。例如,在默认的C语言中,‘[a-dx-z]’相当于‘[abcdxyz]’。许多地区按字典顺序对字符进行排序,在这些地区,‘[a-dx-z]’通常不等同于‘[abcdxyz]’它可能等同于‘[aBbCdxYyZz]’例如。为了获得括号表达式中范围的传统解释,你可以通过将
LC_COLLATE
或LC_ALL
环境变量设置为‘C’,或者启用globasciiranges
shell选项来强制使用C语言。在‘[’和‘]’中,可以指定字符类 使用语法
[:
class:]
,其中 class 是其中之一 POSIX 标准中定义的以下类:alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit
一个字符类可以匹配任何属于该类的字符。
word
字符类可以匹配字母、数字和字符‘_’。在‘[’和‘]’中,可以使用语法
[=
c=]
来指定一个等价类,它匹配所有与字符c具有相同排序权重(由当前locale定义)的字符。在‘[’和‘]’中,语法
[.
symbol.]
与整理符号symbol相匹配。
如果使用extglob
shell选项启用了shopt
内建程序,那么shell可以识别几种扩展的模式匹配操作符。 在下面的描述中,pattern-list是一个由‘|’分隔的一个或多个模式的列表。 当匹配文件名时,dotglob
shell选项决定了被测试的文件名集合,如上所述。 复合模式可以使用以下一个或多个子模式来形成。
?(pattern-list)
匹配零个或一个出现的给定的模式。
*(pattern-list)
匹配零个或更多出现的给定模式。
+(pattern-list)
匹配一个或多个出现的给定的模式。
@(pattern-list)
与给定的模式之一相匹配。
!(pattern-list)
匹配除给定模式之一之外的任何东西。
extglob
选项改变了解析器的行为,因为小括号通常被视为具有句法意义的运算符。 为了确保扩展匹配模式得到正确的解析,在解析包含模式的结构(包括shell函数和命令替换)之前,确保extglob
被启用。
当匹配文件名时,dotglob
shell选项决定了被测试的文件名集合:当dotglob
被启用时,文件名集合包括所有以‘.’开头的文件,但文件名‘.’ 和‘.’必须由以点开头的模式或子模式匹配;当它被禁用时,该集合不包括任何以“.”开头的文件名,除非该模式或子模式以‘.’开头。 如上,‘.’仅在匹配文件名时有特殊含义。
对长字符串进行复杂的扩展模式匹配是很慢的,特别是当模式包含交替和字符串包含多个匹配时。 对较短的字符串使用单独的匹配,或使用字符串数组而不是单一的长字符串,可能会更快。
9 引用删除
在前面的扩展之后,所有未被引用的字符‘’、‘'’和‘"’的出现,如果不是由上述扩展之一产生的,都将被删除。