3.4.1. 总结
在命令被拆分为词根(参见第 1.4.1.1 节)之后,这些标记或单词被扩展或解析。执行的扩展有八种,我们将在下一节中讨论它们的扩展顺序。
在所有扩展之后,执行引号删除。
3.4.2. 大括号扩展
大括号扩展是一种可以生成任意字符串的机制。要进行大括号扩展的模式采用可选PREAMBLE的形式,后跟一对大括号之间的一系列逗号分隔字符串,然后是可选的POSTSCRIPT。前缀添加到大括号中包含的每个字符串,然后将后记附加到每个结果字符串,从左到右扩展。
大括号扩展可能是嵌套的。每个展开字符串的结果不排序;从左到右的顺序被保留:
franky ~> echo sp{el,il,al}l
spell spill spall
大括号扩展在任何其他扩展之前执行,并且任何其他扩展的特殊字符都保留在结果中。它是严格的文本。Bash 不对扩展的上下文或大括号之间的文本应用任何句法解释。为避免与参数扩展发生冲突,字符串“${”不适合大括号扩展。
格式正确的大括号展开必须包含不带引号的左大括号和右大括号,以及至少一个不带引号的逗号。任何格式不正确的大括号扩展都无效。
3.4.3. 波浪号扩展
如果单词以不带引号的波浪号字符 ( “~” ) 开头,则直到第一个不带引号的斜杠(或所有字符,如果没有不带引号的斜杠)之前的所有字符都被视为tilde-prefix。如果波浪号前缀中没有任何字符被引用,波浪号后面的波浪号前缀中的字符将被视为可能的登录名。如果此登录名是空字符串,波浪号将替换为HOME shell 变量的值。如果HOME未设置,则替换执行 shell 的用户的主目录。否则,波浪号前缀将替换为与指定登录名关联的主目录。
如果tilde-prefix是”~+”,shell 变量PWD的值将替换tilde-prefix。如果tilde-prefix为”~-“,则替换 shell 变量OLDPWD的值(如果已设置)。
如果tilde-prefix中波浪号后面的字符由数字 N 组成,可选前缀为“+”或“-”,tilde-prefix将替换为目录堆栈中的相应元素,因为它将显示由dirs调用,其中tilde-prefix中波浪号后面的字符作为参数。如果tilde-prefix(没有波浪号)由一个没有前导“+”或“-”的数字组成,则假定为“+” 。
如果登录名无效,或者波浪号扩展失败,则单词保持不变。
每个变量赋值都会检查紧跟在”:”或”=”之后的未加引号的tilde-prefix。在这些情况下,也执行波浪号扩展。因此,可以在分配给PATH、MAILPATH和CDPATH时使用带有波浪号的文件名,并且 shell 分配扩展值。
franky ~> export PATH="$PATH:~/testdir"
~/testdir将扩展为$HOME /testdir,因此如果$HOME是/var/home/franky,目录/var/home/franky/testdir将添加到PATH变量的内容中。
3.4.4. Shell参数和变量扩展
“ $”字符引入了参数扩展、命令替换或算术扩展。要扩展的参数名称或符号可以用大括号括起来,用于保护要扩展的变量免受紧随其后的字符的影响。
当使用大括号时,匹配的结束大括号第一个“}”,它没有被反斜杠转义,也没有在带引号的字符串中,也没有在嵌入的算术扩展、命令替换或参数扩展中。
参数扩展的基本形式是”${PARAMETER}”。“PARAMETER”的值被替换。当“PARAMETER”是一个多于一位的位置参数时,或者当“PARAMETER”后跟一个不被解释为其名称的一部分的字符时,大括号是必需的。
如果“PARAMETER”的第一个字符是感叹号,Bash 使用由“PARAMETER”的其余部分组成的变量的值作为变量的名称;然后扩展此变量,并将该值用于其余的替换,而不是“PARAMETER”本身的值。这称为间接扩展。(就是会去模糊匹配命令)比如 ${!N},${!R}
您熟悉直接参数扩展,因为它一直在发生,即使在最简单的情况下,例如上面或下面的情况:
franky ~> echo $SHELL
/bin/bash
The following is an example of indirect expansion:
franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX\_PLUGIN\_PATH
请注意,这与echo $N*不同。
如果变量尚不存在,则以下构造允许创建命名变量:
${VAR:=value}
例子:
franky ~> **echo $FRANKY
franky ~> **echo ${FRANKY:=Franky}
Franky
然而,特殊参数,尤其是位置参数,不能以这种方式分配。
3.4.5. 命令替换
命令替换允许命令的输出替换命令本身。当像这样包含命令时会发生命令替换:
$(command)
或者像这样使用反引号:
command
Bash 通过执行 COMMAND 并将命令替换替换为命令的标准输出来执行扩展,并删除任何尾随的换行符。嵌入的换行符不会被删除,但它们可能会在分词过程中被删除。
franky ~> echo `date`
Thu Feb 6 10:06:20 CET 2003
当使用旧式反引号形式的替换时,反斜杠保留其字面含义,除非后面跟着”$”、”`”或”\”。前面没有反斜杠的第一个反引号终止命令替换。使用“$(COMMAND)”形式时,括号之间的所有字符组成命令;没有特殊对待。
命令替换可能是嵌套的。要在使用反引号形式时嵌套,请使用反斜杠转义内部反引号。
如果替换出现在双引号中,则不会对结果执行分词和文件名扩展。
3.4.6. 算术扩展
算术扩展允许对算术表达式求值并替换结果。算术展开的格式为:
$((EXPRESSION))
表达式被视为在双引号内,但括号内的双引号不会被特殊处理。表达式中的所有标记都经过参数扩展、命令替换和引号删除。算术替换可以嵌套。
算术表达式的计算是在固定宽度的整数中完成的,不检查溢出 - 尽管被零除被捕获并被识别为错误。运算符与 C 编程语言中的运算符大致相同。按照优先级递减的顺序,列表如下所示:
Table 3-4. Arithmetic operators
Operator | Meaning |
---|---|
VAR++ and VAR— | 可变后增量和后减量 |
++VAR and —VAR | 可变预增和预减 |
- and + | 一元减号和加号 |
! and ~ | 否定 |
** | 求幂 |
*, / and % | 乘法、除法、余数 |
+ and - | |
< |
左右位移 |
<=,>=, < and > | 比较运算符 |
== and != | 等与不等 |
& | |
^ | |
| | |
&& | |
|| | |
expr ? expr : expr | 三元表达式 |
=, *=, /=, %=, +=, -=, <<=,>>=, &=, ^= and |= | |
, | 表达式之间的分隔符 |
shell 变量允许作为操作数;在计算表达式之前执行参数扩展。在表达式中,shell 变量也可以通过名称来引用,而无需使用参数扩展语法。变量的值在被引用时被计算为算术表达式。shell 变量不需要其整数属性才在表达式中使用。
带有前导 0(零)的常量被解释为八进制数。前导“0x”或“0X”表示十六进制。否则,数字采用”[BASE’#’]N”形式,其中”BASE”是 2 到 64 之间的十进制数,表示算术基数,N 是该基数中的数字。如果省略“BASE’#’”,则使用基数 10。大于 9 的数字依次由小写字母、大写字母、“@”和“_”表示。如果“BASE”小于或等于 36,
运算符按优先级顺序计算。括号中的子表达式首先被评估。
Bash 用户应尽可能尝试使用带方括号的语法:
$[ EXPRESSION ]
但是,这只会计算EXPRESSION的结果,不做任何测试:
franky ~> echo $[365*24]
8760
3.4.7. 进程替换
进程替换支持命名管道 (FIFO) 或/dev/fd方法打开的具名文件。它采取以下形式
<(LIST)
或者
>(LIST)
进程LIST运行时其输入或输出连接到 FIFO 或/dev/fd中的某个文件。作为扩展的结果,此文件的名称作为参数传递给当前命令。如果使用”>(LIST)”形式,写入文件将为LIST提供输入。如果使用“<(LIST)”形式,则应读取作为参数传递的文件以获得LIST的输出。请注意,< 或 > 符号和左括号之间不能出现空格,否则该构造将被解释为重定向。
3.4.8. 分词
shell 会扫描双引号内未出现的参数扩展、命令替换和算术扩展的结果以进行分词。
shell 将$IFS的每个字符视为分隔符,并将其他扩展的结果拆分为这些字符上的单词。如果IFS未设置,或者它的值恰好是默认值”‘
保留显式空参数(””””或”‘’” )。不带引号的隐式空参数由没有值的参数的扩展产生。如果在双引号内扩展了没有值的参数,则会产生并保留空参数。
扩展和分词
如果没有发生扩展,则不执行拆分。
3.4.9. 文件名扩展
分词后,除非设置了-f选项(参见第 2.3.2 节),否则 Bash 会扫描每个单词中的字符”*”、”?” , 和”[“。如果出现这些字符之一,则该单词被视为PATTERN,并替换为按字母顺序排列的与该模式匹配的文件名列表。如果没有找到匹配的文件名,并且 shell 选项nullglob被禁用,则单词保持不变。如果设置了nullglob选项,但没有找到匹配项,则删除该单词。如果启用了 shell 选项nocaseglob,则执行匹配时不考虑字母字符的大小写。
当模式用于文件名生成时,字符“.” 除非设置了 shell 选项dotglob,否则必须显式匹配文件名的开头或紧跟在斜杠之后的位置。匹配文件名时,斜杠字符必须始终显式匹配。在其他情况下,“。” 字符没有特殊处理。
GLOBIGNORE shell变量可用于限制匹配模式的文件名集。如果设置了 GLOBIGNORE,则从匹配列表中删除每个也匹配GLOBIGNORE中的模式之一的匹配文件名。文件名. 和..总是被忽略,即使设置了 GLOBIGNORE。但是,设置GLOBIGNORE具有启用dotglob shell 选项的效果,因此所有其他以“.”开头的文件名 会匹配。
https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html