3.5 Shell的扩展

评论 0 浏览 0 2023-01-16

扩展是在命令行被分割成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]},其中xy是整数或字母,而incr是一个可选的增量,是一个整数。 当提供整数时,表达式扩展到xy之间的每个数字,包括在内。 提供的整数可以以‘0’为前缀,强制每个项具有相同的宽度。当xy以0开头时,shell会尝试强制所有生成的术语包含相同数量的数字,必要时进行零填充。当提供字母时,表达式会使用默认的C语言扩展到xy之间的每个字符。 注意xy必须是相同的类型(整数或字母)。 当提供增量时,它被用作每个项之间的差异。默认的增量是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 目录堆栈)。如果没有波浪号的波浪号前缀由没有前导‘+’或‘-’ 的数字组成,则假定‘+’。

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

每个变量的赋值都要检查紧跟在‘:’或第一个‘=’之后的未引用的波浪号前缀。 在这些情况下,波浪号扩展也会被执行。 因此,可以在赋值给PATHMAILPATHCDPATH时使用带有波浪号的文件名,并且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指定的字符开始,延伸到该值的末端。lengthoffset是算术表达式(见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

如果参数是‘’或‘*’,结果是lengthoffset开始的位置参数。 负的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对其值的最长匹配被替换为stringstring经历了波浪号扩展、参数和变量扩展、算术扩展、命令和进程替换以及引号删除。 匹配根据下面描述的规则进行(见8.1 模式匹配)。

如果parameterpattern之间有两个斜杠(上述第二种形式),那么模式的所有匹配将被替换为字符串。 如果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的值不是默认值,那么在词的开头和结尾的空白字符spacetabnewline的序列被忽略,只要空白字符在IFS的值中(一个IFS的空白字符)。 IFS中任何不是IFS的空白字符,连同任何相邻的IFS的空白字符,限定一个字段。一串IFS空白字符也被视为定界符。 如果IFS的值为空,则不会发生分词。

明确的空参数(""'')被保留下来,并作为空字符串传递给命令。 没有引号的隐式空参数,由没有值的参数扩展而来,被删除。 如果一个没有值的参数在双引号内被扩展,会产生一个空参数,并被保留下来,作为空字符串传递给命令。 当一个引号的空参数作为一个单词的一部分出现,而这个单词的扩展是非空的,空参数被删除。 也就是说,单词-d''在分词和空参数删除后变成了-d

请注意,如果没有发生扩展,就不会进行分割。

8 文件名扩展

在分词之后,除非设置了-f选项(参见1 Set 内置程序),否则Bash会扫描每个词,以寻找‘*’、‘?’和‘[’等字符。如果这些字符之一出现,并且没有引号,那么这个词将被视为模式,并被替换为按字母排序的匹配模式的文件名列表(见8.1 模式匹配)。如果没有找到匹配的文件名,并且禁用了shell选项nullglob,那么该词将保持不变。 如果设置了nullglob选项,并且没有找到匹配的文件名,那么该词将被删除。 如果设置了failglobshell选项,并且没有找到匹配的文件名,那么将打印一条错误信息,并且不执行该命令。 如果启用了shell选项nocaseglob,那么进行匹配时将不考虑字母字符的大小写。

当模式用于文件名扩展时,文件名开头或斜杠后面的字符‘.’必须显式匹配,除非设置了 shell 选项 dotglob。为了匹配文件名“.”和“..”,模式必须以“.”开头(例如,“.?”),即使设置了dotglob。如果启用了globskipdots shell 选项, 文件名‘.’ 和 ‘..’ 永远不会匹配,即使模式以“.”开头。当不匹配文件名时,‘.’字符不会被特殊对待。

当匹配文件名时,斜线字符必须总是由模式中的斜线明确匹配,但在其他匹配情况下,它可以由一个特殊的模式字符匹配,如下所述(见模式匹配)。

参见2 Shopt 内置程序中对shopt的描述,以了解对nocaseglobnullglobglobskipdotsfailglobdotglob等选项的描述。

GLOBIGNORE shell变量可以用来限制匹配模式的文件名集合。如果设置了GLOBIGNORE,每一个与GLOBIGNORE中的模式相匹配的文件名都会从匹配列表中删除。 如果设置了nocaseglob选项,对GLOBIGNORE中的模式进行匹配时不考虑大小写。 当GLOBIGNORE被设置且不为空时,文件名...总是被忽略。然而,将GLOBIGNORE设置为非空值具有启用dotglob壳选项的效果,因此所有其他以‘.’开头的文件名将被匹配。 要获得忽略以‘.’开头的文件名的旧行为,请将‘.*’作为GLOBIGNORE中的模式之一。 当GLOBIGNORE未设置时,dotglob选项被禁止。

8.1 模式匹配

除了下面描述的特殊模式字符外,任何出现在模式中的字符都会与自己匹配。 NUL字符不能出现在模式中。 反斜杠可以转义后面的字符;在匹配时,转义的反斜杠会被丢弃。 如果要按字面意思匹配,特殊模式字符必须被引号化。

特殊模式的字符有以下含义。

*

匹配任何字符串,包括空字符串。 当globstar shell选项被启用,并且‘*’被用于文件名扩展上下文时,两个相邻的‘*’作为单个模式使用将匹配所有文件和零个或多个目录和子目录。如果后面有一个‘/’,两个相邻的‘*’将只匹配目录和子目录。

?

匹配任何一个单一的字符。

[…]

匹配任何一个被包围的字符。一对用连字符隔开的字符表示一个范围表达式;在这两个字符之间的任何字符(包括在内),使用当前地区的排序和字符集,都被匹配。如果‘[’后的第一个字符是‘!’或‘^’,那么任何未被包围的字符都被匹配。A ‘-’可以通过将其作为集合中的第一个或最后一个字符进行匹配。A ‘]’可以通过将其作为集合中的第一个字符进行匹配。 范围表达式中字符的排序顺序以及范围中包含的字符由当前的locale以及LC_COLLATELC_ALL shell变量的值(如果设置)决定。

例如,在默认的C语言中,‘[a-dx-z]’相当于‘[abcdxyz]’。许多地区按字典顺序对字符进行排序,在这些地区,‘[a-dx-z]’通常不等同于‘[abcdxyz]’它可能等同于‘[aBbCdxYyZz]’例如。为了获得括号表达式中范围的传统解释,你可以通过将LC_COLLATELC_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 引用删除

在前面的扩展之后,所有未被引用的字符‘’、‘'’和‘"’的出现,如果不是由上述扩展之一产生的,都将被删除。

最后更新2023-02-20
0 个评论
上一篇: 3.4 shell参数
下一篇: 3.6 重定向