3.4 Shell 参数(Shell Parameters)
参数(parameter)是一个用于存储值的实体。它可以是一个名称(name),一个数字或一个下面列出的特殊字符。变量是一个以名称命名的参数。一个变量具有一个值和零个或多个属性(attributes)。属性是使用内建命令“delclare”(参见 4.2《Bash 内建命令》)进行分配的。
如果给一个参数分配了一个值,则该参数就是被设置了的。空(null)字符串也是一个可用的值。一旦设置了一个变量,它只能使用内建命令“unset”进行释放。
变量可以使用下面的语法格式进行赋值:
name=[value]
如果没有给出值(value),则分配一个空字符串给变量。值可以由波浪扩展、参数和变量扩展、命令替换、算术扩展和引用移除得到。如果变量设置了整数(integer)属性,其值就由算术扩展运算得出,即使没有使用“$((…))”扩展格式(算术扩展参见 3.5.5《算术扩展》)。在这里不会执行单词分割,但下面提到的“$@”是个例外。也不会执行文件名扩展。赋值语句也可以作为参数(argument)出现在内建命令“alias”、“declare”、“typeset”、“export”、“readonly”和“local”中。当在 POSIX 模式下,这些内建命令可以出现在一个或多个内建命令“command”实例后的命令中,并且保留这些赋值语句的属性。
在赋值语句为一个 shell 变量或索引数组进行赋值的上下文中,“+=”操作符可以对变量之前的值进行累加操作或对数组进行追加操作。这包括像“declare”这样的内建命令的参数接受赋值语句。当“+=”应用于一个具有整数(integer)属性的变量时,其值就被当做算术扩展进行运算,并将该值加到变量当前值上。当“+=”作为复合赋值应用于数组变量(参见 6.7《数组》)时,变量值不会像使用“=”赋值那样被释放,新值会添加到第一个大于数组最大索引的位置(作用于索引数组),或在关联数组中附加一对键值。当其应用于字符串值变量时,该值扩展后会追加到变量值的后面形成新的字符串。
可以使用带有“-n”选项的内建命令“declare”或“local”给变量分配一个“nameref”属性来创建名称参考变量或参考到其它变量上。这样可以对变量进行间接操作。无论何时对名称参考变量进行引用、赋值、释放或更改其属性(除了使用或改变它自己的名称参考“nameref”属性),这其实都是应用于名称参考变量值所指向的变量值上。名称参考通常用在 shell 函数内部,用来引用以函数参数形式传入的变量名。例如,如果一个变量名作为第一个参数传入 shell 函数中,在函数中使用“declare -n ref=$1”创建变量“ref”来引用传进来的变量名。对于变量“ref”的引用、赋值和属性变更,都视为对传进来的由“$1”代表的变量名的变量进行的操作。
如果在 for 循环中使用名称参考作为其控制变量,在循环执行中,所生成的单词列表能够作为 shell 变量列表,在列表中的每一个单词都会轮流建立名称参考。数组变量不能赋予“nameref”属性。然而,名称参考变量可以引用数组变量和带下标的数组变量。可以使用带有“-n”选项的“unset”内建命令释放名称参考。否则,如果执行了带有名称参考变量为参数的“unset”命令,则该参考变量所引用的变量将会被释放。
3.4.1 位置参数(Positional Parameters)
位置参数是一个使用一位或多位数字表示的参数,除了一位数字的“0”。当调用 shell 时,位置参数来自于 shell 的参数(arguments),并且可以使用内建命令“set”对其重新赋值。位置参数“N”可以被引用为“${N}”,或当“N”由一位数字组成时可引用为“$N”。不能使用赋值语句对位置参数进行赋值。内建命令“set”和“shift”(参见第 4 章《Shell 内建命令》)可以对其进行设置和释放。当一个 shell 函数执行时,位置参数是可以被临时替换掉的。
当一个位置参数是由多于一位的数字组成的,它必须使用大括号括起来。
3.4.2 特殊参数(Special Parameters)
shell 会特殊对待一些参数。这些参数可以被引用,但不能进行赋值。
*
“$*”扩展为从 1 开始的位置参数。当该扩展没有使用双引号括起来时,每一个位置参数扩展为独立的单词。在其执行的上下文中,这些单词将进一步进行词分割和文件名扩展。当扩展出现在双引号内时,使用特殊变量 IFS 的第一个字符作为分隔符,将每一个参数连接起来成为一个单词。这就是说,“"\$\*"”等同于“"$1c$2c"”,这里的 c 代表的是 IFS 变量的第一个字符。如果 IFS 是未设置的,则使用空格作为参数的分隔符。如果 IFS 是空,则连接参数而不使用分隔符。
@
“$@”扩展为从 1 开始的位置参数。在执行单词分割的上下文中,将每一个位置参数扩展为分开的单词;如果它没有被双引号括起来,这些单词将进行单词分割。在没有进行单词分割的上下文中,位置参数扩展为用空格分开的单个单词。当扩展出现在双引号里时,并且执行了单词分割,每一个单词扩展为分开的单词。也就是说,“"$@"”等同于“"$1" "$2" ...”。如果在一个单词中出现双引号扩展,第一个参数的扩展连接到原始单词的开始部分,最后一个参数的扩展连接到原始单词的结束部分。当没有位置参数时,"$@"和$@扩展将不会得到任何结果(也就是移除了它们)。
#
“$#”扩展为以十进制数表示的位置参数的个数。
?
“$?”扩展为最近一次前台管道执行的退出状态。
-
“$-”扩展为基于调用指定的当前选项标志位,可由内建命令 set 指定,或由 shell 自身指定(像“-i”选项)。
$
“$$”扩展为 shell 的进程 ID。在“()”子 shell 中,它扩展为调用 shell 的进程 ID,并非是子 shell 的 ID。
!
“$!”扩展为最近一次置入后台的作业的进程 ID,不管其是执行的异步命令或使用内建命令“bg”(参见 7.2《作业控制的内建命令》)的作业。
0
“$0”扩展为 shell 名或 shell 脚本名。这是在 shell 初始化时设置的。如果调用 Bash 时跟随一个命令文件(参见 3.8《Shell 脚本》),“$0”则设置为这个文件的名字。如果调用 Bash 时使用了“-c”选项(参见 6.1《调用 Bash》),则“$0”设置为在执行的命令字符串后的第一个参数,如果出现一个的话。否则,它将设置为由参数零给出的用于调用 Bash 的文件名。