shell脚本系列:6、shell扩展


文章目录


在将命令行分割为多个令牌之后,将在命令行上执行扩展。进行了七种扩展:

  • 花括号{}扩展
  • 波浪号~扩展
  • 参数和变量扩展
  • 命令置换
  • 算术扩展
  • 词的拆分
  • 文件名扩展

• ​​Brace Expansion​

括号内表达式的展开

• ​​Tilde Expansion​

扩展~字符

• ​​Shell Parameter Expansion​

Bash如何将变量展开为它们的值。

• ​​Command Substitution​

使用命令的输出作为参数。

• ​​Arithmetic Expansion​

如何在shell扩展中使用算术

• ​​Process Substitution​

对命令进行读写的一种方式

• ​​Word Splitting​

如何讲展开的结果分解成独立的论证

• ​​Filename Expansion​

指定匹配模式的文件名的一种简写。

• ​​Quote Removal​

如何以及何时从单词中删除引号字符。

展开顺序为:大括号展开;波浪号展开、参数和变量展开、算术展开和命令替换(以从左到右的方式完成);分词;和文件名扩展。

在支持它的系统上,还有一个额外的扩展:进程替代。这与波浪号、参数、变量、算术展开和命令替换同时执行。

在执行这些展开之后,原始单词中的引号字符将被删除,除非它们本身也被引用(删除引号)。

只有大括号展开、分词和文件名展开才能增加展开的词数;其他扩展将单个单词扩展为单个单词。唯一的例外是“shell脚本系列:6、shell扩展_大括号*(参见​​​特殊参数​​​)的展开,以及“shell脚本系列:6、shell扩展_大括号_02{name[*]}(参见​​​数组​​)。

在所有展开之后,将执行引用删除(参见​​引用删除​​)。

1. 花括号扩展

大括号展开是一种可以生成任意字符串的机制。这种机制类似于文件名扩展(请参阅文件名扩展),但生成的文件名不需要存在。展开大括号的模式采用可选的前缀形式,后面是一系列逗号分隔的字符串或一对大括号之间的序列表达式,后面是可选的后记。在大括号中包含的每个字符串前面加上序言,然后将后记追加到每个结果字符串,从左到右展开。

大括号展开可以嵌套。每个展开字符串的结果不进行排序;保留了从左到右的顺序。例如:

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。当提供字符时,表达式使用默认的C语言环境,按照字典顺序扩展到x和y之间的每个字符(包括y)。注意,x和y必须是相同的类型。当提供增量时,它被用作每个项之间的差值。默认增量为1或-1。

大括号展开在任何其他展开之前执行,并且在结果中保留对其他展开特殊的任何字符。它是严格的文本。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的用户的主目录。否则,波浪号前缀将被替换为与指定登录名相关联的主目录。

如果波浪号前缀是’ ~+ ‘,则shell变量​​PWD​​​的值将替换波浪号前缀。如果波浪号前缀是’ ~- ',则替换shell变量​​OLDPWD​​的值(如果设置了它)。

如果波浪号前缀中波浪号后面的字符由数字N组成,可以选择前缀为+或-,则波浪号前缀将被目录堆栈中的相应元素替换,因为它将被内置的​​dirs​​​以波浪号前缀中的波浪号后面的字符作为参数来调用(参见​​目录堆栈​​)。如果没有波浪号的波浪号前缀由一个没有前导+或-的数字组成,则假定为+。

如果登录名无效,或波浪号展开失败,则该词保持不变。

检查每个变量赋值是否有紧跟在’:‘或第一个’ = '后面的未加引号的波浪前缀。在这些情况下,还需要进行波浪号展开。因此,可以在给​​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还会对它们执行波浪展开(请参阅Shell参数)。Bash在POSIX模式下不会这样做,除了上面列出的声明命令。

3. shell参数扩展

'$'字符引入参数展开、命令替换或算术展开。要展开的参数名或符号可以用大括号括起来,大括号是可选的,但用于保护要展开的变量不受紧随其后的字符的影响,这些字符可能被解释为名称的一部分。

当使用大括号时,匹配的结束大括号是第一个’}’,没有被反斜杠转义,也没有在带引号的字符串中,也没有在嵌入式算术展开、命令替换或参数展开中。

参数展开的基本形式是${parameter}。参数值被替换。参数是上面描述的shell参数(参见​​shell参数​​​)或数组引用(参见​​数组​​)。当parameter是一个具有多个数字的位置参数时,或者当parameter后面跟着一个不能解释为其名称一部分的字符时,就需要使用大括号。

如果parameter的第一个字符是感叹号(!),而parameter不是名称,那么它引入了一种间接级别。Bash使用展开其余参数所形成的值作为新参数;然后展开该参数,并在展开的其余部分中使用该值,而不是对原始参数进行展开。这就是所谓的间接扩张。该值可以进行波浪号展开、参数展开、命令替换和算术展开。如果parameter是一个nameref,则扩展为parameter引用的变量的名称,而不是执行完全的间接展开。例外情况是shell脚本系列:6、shell扩展_大括号_03

在下面的每一种情况中,word都可以进行波浪号展开、参数展开、命令替换和算术展开。

当不执行子字符串展开时,Bash会使用下面描述的形式(例如,’:- ')测试未设置的参数或空参数。省略冒号只会导致对未设置的参数进行测试。换句话说,如果包含冒号,操作符将测试两个形参是否存在以及它的值是否不为空;如果省略冒号,操作符只测试是否存在。

${parameter:-word}

如果parameter未设置或为null,则$parameter为word。否则,parameter值不变。

${parameter:=word}

如果parameter为unset或null,则将word的展开值赋给parameter。然后替换parameter的值。位置参数和特殊参数不能以这种方式分配。

${parameter:?word}

如果parameter为null或unset, word的扩展(或者如果word不存在,则会产生此效果的消息)将写入标准错误,如果shell不是交互式的,则退出。否则,将替换parameter的值。

${parameter:+word}

如果parameter为null或unset,则不替换任何内容,否则替换word的扩展。

${parameter:offset}
${parameter:offset:length}

这称为子字符串展开。它扩展到参数值的长度字符,从offset指定的字符开始。如果参数是’ @ ‘,一个下标为’ @ ‘或’ * '的索引数组,或一个关联数组名,结果如下所述不同。如果省略了length,它将扩展到parameter值的子字符串,从offset指定的字符开始,一直扩展到值的末尾。length和offset是算术表达式(参见​​Shell算术​​)。

如果offset的计算结果小于零,则该值将用作参数值末尾的字符中的偏移量。如果length的计算结果小于零,则它被解释为参数值末尾的字符偏移量,而不是字符数,展开是偏移量和结果之间的字符。请注意,负偏移量必须与冒号间隔至少一个空格,以避免与“:-”展开符混淆。

下面是一些说明参数和下标数组的子字符串展开的例子:

$ 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}

如果parameter为’ @ ',则结果是从offset开始的长度位置参数。负偏移量相对于大于最大位置参数的1,所以-1的偏移量计算为最后一个位置参数。如果长度计算结果小于零,则表示展开错误。

下面的例子演示了使用位置参数展开子字符串:

$ 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]}​​开头的数组长度成员。负偏移量相对于大于指定数组的最大索引的1。如果长度计算结果小于零,则表示展开错误。

这些例子展示了如何在索引数组中使用子字符串展开:

$ 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@}

展开为名称以前缀开头,由IFS特殊变量的第一个字符分隔的变量名。当使用“@”并在双引号中展开时,每个变量名展开为一个单独的单词。

${!name[@]}
${!name[*]}

如果name是一个数组变量,则展开为以name分配的数组索引(键)列表。如果name不是数组,则如果name设置为0,否则为null。当使用“@”并在双引号内展开时,每个键展开为一个单独的单词。

${#parameter}

将替换参数扩展值的字符长度。如果parameter是’ * ‘或’ @ ‘,则替换的值是位置参数的数量。如果parameter是一个下标为’ * ‘或’ @ '的数组名称,则替换的值是数组中的元素数量。如果parameter是一个下标为负数的索引数组名称,则该数字被解释为相对于大于parameter的最大索引的1,因此负数索引从数组的末尾开始计数,而-1索引则引用最后一个元素。

${parameter#word}
${parameter##word}

这个词被扩展为生成一个模式,并根据下面描述的规则进行匹配(参见​​模式匹配​​)。如果模式匹配参数展开值的开头,则展开的结果是删除了最短匹配模式(# case)或最长匹配模式(## case)的参数展开值。如果参数是@或*,模式删除操作依次应用于每个位置参数,展开就是结果列表。如果parameter是一个下标为@或*的数组变量,则模式删除操作依次应用于数组的每个成员,展开就是结果列表。

${parameter%word}
${parameter%%word}

这个词被扩展为生成一个模式,并根据下面描述的规则进行匹配(参见模式匹配)。如果模式匹配参数扩展值的末尾部分,则扩展的结果是删除了最短匹配模式(% case)或最长匹配模式(%% case)的参数值。如果参数是@或*,模式删除操作依次应用于每个位置参数,展开就是结果列表。如果parameter是一个下标为@或*的数组变量,则模式删除操作依次应用于数组的每个成员,展开就是结果列表。

${parameter/pattern/string}

模式被展开以产生与文件名展开一样的模式。参数被展开,模式对其值的最长匹配被替换为字符串。根据下面描述的规则执行匹配(请参见​​模式匹配​​)。如果pattern以/开头,则pattern的所有匹配都被替换为string。通常只替换第一个匹配项。如果pattern以#开头,它必须匹配parameter展开值的开头。如果pattern以%开头,它必须匹配参数展开值的末尾。如果string为空,模式匹配将被删除,/后面的模式可能被省略。如果启用了nocasematch shell选项(请参阅the shopt Builtin中对shopt的描述),则执行匹配而不考虑字母字符的大小写。如果parameter为@或*,则依次对每个位置参数应用替换操作,展开就是结果列表。如果parameter是下标为@或*的数组变量,则依次对数组的每个成员应用替换操作,展开就是结果列表。

${parameter^pattern}
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}

此扩展修改参数中字母字符的大小写。模式被展开以产生与文件名展开一样的模式。参数扩展值中的每个字符都将根据模式进行测试,如果它与模式匹配,则将转换其大小写。模式不应该尝试匹配多个字符。运算符将小写字母匹配模式转换为大写;’,‘操作符将匹配的大写字母转换为小写字母。’‘和’,‘展开对展开值中的每个匹配字符进行转换;’’ 和’,'展开只匹配并转换展开值中的第一个字符。如果省略了模式,它将被视为?,它匹配每个字符。如果参数是@或*,则依次对每个位置参数应用大小写修改操作,展开就是结果列表。如果parameter是一个下标为@或*的数组变量,则大小写修改操作依次应用于数组的每个成员,展开就是结果列表。

${parameter@operator}

展开是参数值或参数本身信息的转换,具体取决于operator的值。每个操作符都是一个字母:

  • ​U​​展开项是一个字符串,它是参数的值,小写字母转换为大写字母。
  • ​u​​展开项是一个字符串,如果是字母,则是第一个字符转换为大写的参数值。
  • ​L​​展开项是一个字符串,是参数值的大写字母转换为小写字母。
  • ​Q​​展开项是一个字符串,它是参数的值,以可以作为输入重用的格式引用。
  • ​E​​展开是一个字符串,它是参数的值,带有反斜杠转义序列,使用$’…'引用机制展开。
  • ​P​​​展开是一个字符串,它是将parameter的值当作提示字符串展开的结果(请参见​​控制提示符​​)。
  • ​A​​展开是一个赋值语句或声明命令形式的字符串,如果求值,将使用其属性和值重新创建参数。
  • ​K​​​生成一个可能用引号括起来的parameter值版本,但它将索引数组和关联数组的值打印为一个用引号括起来的键-值对序列(参见​​数组​​)。
  • ​a​​展开是由表示参数属性的标志值组成的字符串。

如果参数是’ @ ‘或’ * ‘,则依次对每个位置参数应用操作,展开就是结果列表。如果parameter是一个下标为’ @ ‘或’ * '的数组变量,则该操作依次应用于数组的每个成员,展开就是结果列表。

扩展的结果受下面描述的分词和文件名扩展的影响。

4. 命令替换

命令替换允许命令的输出替换命令本身。当一个命令用如下方式括起来时,就会发生命令替换:

$(command)

或:

`command`

Bash通过在子shell环境中执行命令并使用命令的标准输出替换命令替换,并删除末尾的换行符来执行展开。嵌入式换行不会被删除,但是在分词时可以删除它们。命令替换​​$(cat file)​​​可以被等价但更快的​​$(< file)​​替代。

当使用旧式的反引号形式替换时,反斜杠保留其字面意思,除非后面跟着’ $ ‘、​​' `'​​​ ,或’ \ '。第一个没有反斜杠的反引号终止命令替换。当使用​​$(command)​​形式时,圆括号之间的所有字符组成命令;没有人受到特别对待。

命令替换可以是嵌套的。若要使用反引号形式进行嵌套,请使用反斜杠转义内部反引号。

如果替换出现在双引号内,则不会对结果执行单词分割和文件名展开。

zy@LS2-R910CQQT:~$ $(echo ls)

5. 算术扩展

算术展开允许对算术表达式求值和替换结果。算术展开的格式为:

$(( expression ))

表达式被当作在双引号内处理,但是括号内的双引号没有被特别处理。表达式中的所有标记都经过参数和变量展开、命令替换和引号删除。结果被视为要求值的算术表达式。算术展开可以嵌套。

根据下面列出的规则执行计算(请参阅​​Shell算术​​)。如果表达式无效,Bash将打印一条消息,指示标准错误失败,并且不会发生替换。

6. 进程替换

进程替换允许使用文件名引用进程的输入或输出。它的形式是

<(list)

或:

>(list)

进程列表是异步运行的,其输入或输出显示为文件名。这个文件名作为参数传递给当前命令作为展开的结果。如果使用>(list)表单,向文件写入将为list提供输入。如果使用<(list)形式,则应该读取作为参数传递的文件以获得list的输出。注意之间不能有空格。否则该结构将被解释为重定向。支持命名管道(FIFOs)或命名打开文件的​​/dev/fd​​方法的系统支持进程替换。

如果可用,进程替换将与参数和变量展开、命令替换和算术展开同时执行。

7. 分词

shell扫描参数展开、命令替换和算术展开的结果,这些结果没有出现在双引号中以进行单词拆分。

shell将​​$IFS​​的每个字符视为分隔符,并使用这些字符作为字段终止符将其他展开的结果分割为单词。如果IFS未设置,或其值恰好为<space><tab><newline>,则默认为<space>, <tab>和<newline>忽略前面展开结果的开始和结束处,并且任何不在开始或结束处的IFS字符序列用于分隔单词。如果IFS的值不是默认值,则忽略单词开头和结尾的空格字符空格、制表符和换行符序列,只要空格字符在IFS的值中(一个IFS空格字符)。IFS中的任何非IFS空白字符,以及任何相邻的IFS空白字符,都分隔字段。IFS空白字符序列也被视为分隔符。如果IFS的值为null,则不拆分。

显式的空参数("“或”)被保留并作为空字符串传递给命令。由于展开没有值的形参而产生的未带引号的隐式null实参将被删除。如果在双引号内展开没有值的参数,将产生一个空参数,并保留该参数并将其作为空字符串传递给命令。当带引号的空参数作为展开为非空的单词的一部分出现时,空参数将被删除。也就是说,单词-d "在单词拆分和空参数移除后变成-d。

注意,如果没有展开,则不执行分裂。

8. 文件名扩展

​模式匹配​​:shell如何匹配模式。

拆字后,除非设置了-f选项(参见​​内置设置​​​),Bash会扫描每个单词中的字符*、?,和[。如果其中一个字符出现了,并且没有被引用,那么这个单词就被视为一个模式,并被匹配该模式的按字母顺序排序的文件名列表替换(参见​​模式匹配​​​)。如果没有找到匹配的文件名,并且禁用shell选项​​nullglob​​​,则该单词将保持不变。如果设置了​​nullglob​​​选项,并且没有找到匹配项,则删除该单词。如果设置了​​failglob​​​shell选项,但没有找到匹配项,则返回错误提示,不执行命令。如果启用了shell选项​​nocaseglob​​,则执行匹配而不考虑字母字符的大小写。

当一个模式用于文件名扩展时,字符’.‘必须显式匹配文件名的开头或紧跟着斜杠的位置,除非设置了shell选项​​dotglob​​​。文件名’.'和‘. .‘必须始终显式匹配,即使设置了​​dotglob​​。在其他情况下,’.'字符没有得到特别对待。

当匹配文件名时,斜杠字符在模式中必须始终由斜杠显式匹配,但在其他匹配上下文中,它可以由下面描述的特殊模式字符匹配(参见​​模式匹配​​)。

有关​​nocaseglob​​​、​​nullglob​​​、​​failglob​​​和​​dotglob​​​选项的描述,请参见​​the shopt Builtin​​​中对​​shopt​​的描述。

可以使用​​GLOBIGNORE​​​ shell变量来限制匹配模式的文件名集。如果设置了​​GLOBIGNORE​​​,则将从匹配列表中删除与​​GLOBIGNORE​​​中的某个模式匹配的每个匹配文件名。如果设置了​​nocaseglob​​​选项,就会不考虑大小写而执行​​GLOBIGNORE​​​中的模式匹配。文件名​​.​​​和​​. .​​​当​​GLOBIGNORE​​​设置为非空时,总是被忽略。但是,将​​GLOBIGNORE​​​设置为非空值的效果是启用​​dotglob​​​ shell选项,因此其他所有以​​.​​​将匹配。获取忽略以​​.​​​创建​​.*​​​部分的​​GLOBIGNORE​​​中的一个模式。当不设置​​GLOBIGNORE​​​时,禁用​​dotglob​​选项。

8.1 模式匹配

模式中出现的任何字符,除了下面描述的特殊模式字符外,都与自身匹配。NUL字符不能出现在模式中。反斜杠转义以下字符;当匹配时,转义反斜杠将被丢弃。如果要按字面匹配,特殊模式字符必须用引号括起来。

特殊模式字符的含义如下:

  • ​*​​匹配任何字符串,包括空字符串。当启用了globstar shell选项,并且’ * ‘被用于文件名扩展上下文时,两个相邻的’ * ‘被用作单个模式将匹配所有文件和零个或多个目录和子目录。如果后面跟一个’ / ‘,两个相邻的’ * '将只匹配目录和子目录。
  • ​?​​匹配任意单个字符
  • ​[…]​​​匹配任何包含的字符。由连字符分隔的一对字符表示一个范围表达式;任何位于这两个字符之间的字符(包括使用当前区域设置的排序序列和字符集)都将被匹配。如果[后面的第一个字符是!或者匹配任何不包含的字符。A -可以作为集合中的第一个或最后一个字符进行匹配。A]可以通过包含它作为集合中的第一个字符来匹配。范围表达式中字符的排序顺序由当前区域设置和LC_COLLATE和LC_ALL shell变量的值(如果设置)决定。
    例如,在默认的C语言环境中,[a-dx-z]等同于[abcdxyz]。许多区域设置按字典顺序对字符进行排序,在这些区域设置中[a-dx-z]通常不等同于[abcdxyz];例如,它可能等价于[aBbCcDdxXyYz]。要获得方括号表达式中范围的传统解释,可以通过将LC_COLLATE或LC_ALL环境变量设置为值C来强制使用C语言环境,或者启用globasciiranges shell选项。
    在’[‘和’]'内,字符类可以使用语法[:class:]来指定,其中class是POSIX标准中定义的以下类之一:
    ​​​alnum alpha ascii blank cntrl digit graph lower print punct space upper word xdigit​​​字符类与属于该类的任何字符匹配。单词字符类匹配字母、数字和字符’ _ '。
    在’[‘和’]'内,可以使用语法[=c=]指定一个等价类,它匹配与字符c具有相同排序权重(由当前区域设置定义)的所有字符。
    在’[‘和’]'中,语法[.symbol.]匹配排序符号符号。

如果使用内置的shopt启用了​​extglob​​ shell选项,那么可以识别几个扩展模式匹配操作符。在下面的描述中,模式列表是一个由’ | '分隔的一个或多个模式组成的列表。复合模式可以使用以下一种或多种子模式形成:

  • ​?(pattern-list)​​匹配零个或一个给定模式。
  • ​*(pattern-list)​​匹配零次或多次给定模式。
  • ​+(pattern-list)​​匹配给定模式的一次或多次出现。
  • ​@(pattern-list)​​匹配给定的模式之一。
  • ​!(pattern-list)​​匹配除一个模式以外的任何模式。

针对长字符串的复杂扩展模式匹配速度很慢,特别是当模式包含交替而字符串包含多个匹配时。对较短的字符串使用单独的匹配,或者使用字符串数组代替单一的长字符串,可能更快。

9. 引号去除

在前面的展开之后,所有非由上述展开之一产生的字符​​\​​​、​​’​​​和​​"​​都将被删除。