Bash 参数扩展新特性

作者:Mitch Frazier

bash 手册页接近 4 万字。它虽然不像战争与和平那么长,但在廉价小说书架上也能占有一席之地。鉴于 bash 文档的篇幅,在查看手册页时很容易错过有用的功能。因此,为了寻找新功能,偶尔重温手册页可能是有益的。

今天感兴趣的小节是参数扩展——即,$var的多种形式。不过,不要被这个名称所迷惑,它实际上是关于参数变量扩展。

我不会在这里介绍参数扩展的所有不同形式,只介绍一些我认为可能不如其他形式广为人知的形式。如果您完全不熟悉参数扩展,请查看我很久以前的文章或互联网上其他地方的许多文章之一。

大小写转换

使用以下命令将字符串转换为大写的日子已经一去不复返了tr '[[:lower:]]' '[[:upper:]]'将字符串转换为大写

$ a=hello
$ echo ${a^}       # First character only
Hello
$ echo ${a^^}      # All characters
HELLO

以及转换为小写

$ a=HELLO
$ echo ${a,}       # First character only
hELLO
$ echo ${a,,}      # All characters
hello

您还可以在 operator 之后指定一个字符,并且只更改匹配字符的大小写

$ a=hello
$ echo ${a^l}      # First character if it is an 'l'
hello
$ echo ${a^^ll}    # All characters that are 'l's
heLLo
以某些前缀开头的名称

需要变量名与特定前缀匹配的所有变量的列表吗?这样做

$ mya=1
$ myb=2
$ yourc=3
$ echo ${!my*}
mya myb
间接引用

Bash 甚至可以让您体验到 C 和汇编编程以及使用间接寻址的美好旧时光——好吧,有点像

$ var=somevalue
$ var_name=var
$ echo ${!var_name}
somevalue

这里发生的事情是var_name的值为您提供了要扩展的实际变量的名称。然后扩展该变量并成为扩展的结果。在本例中,“var_name”的值为“var”,因此变量“var”被扩展以产生最终值“somevalue”。

简要介绍命名引用

作为一个题外话,因为它实际上与“参数扩展”无关,让我们快速了解一下 bash 中的命名引用。命名引用变量是一个引用另一个变量的变量

$ var=no
$ declare -n ref=var   # -n == nameref
$ ref=yes
$ echo $ref
yes

变量“ref”是对变量“var”的引用。当您赋值给“ref”时,实际上更改了“var”的值。这在通过将变量名称传递给函数来从函数中获取值时特别方便

$ cat nref.sh
function func()
{
    local -n up_value=$1  # -n == nameref
    up_value=new_value
    echo "Changing '${!up_value}' in ${FUNCNAME[0]}"
}

aval=old_value
echo
echo "Before function call, aval is $aval"
func aval  # pass var *name* to func
echo "After function call, aval is $aval"

运行该命令,您会得到

$ bash nref.sh
Before function call, aval is old_value
Changing 'aval' in func
After function call, aval is new_value

由于命名引用变量是自动间接引用的,因此您无需使用感叹号扩展来获取被引用变量的值;正常的$var扩展即可。在命名引用的情况下,感叹号扩展会产生不同的结果:被引用变量的名称。因此,这个小小的题外话毕竟还是与参数扩展有关。

转换

还有许多形式为${var@?}的扩展,其中“?”是字母“Q”、“E”、“P”、“A”或“a”之一,可以转换值或获取有关变量本身的信息。例如

$ declare -a array=(1 2)
$ echo Attributes: ${array@a}
Attributes: a         # i.e. array was declared with -a

查看手册页以获取有关这些“@”扩展的更多信息。

未设置或空

最后总结一下,在阅读参数扩展部分时,另一个容易被忽略的细微之处与许多扩展中的冒号(:)有关。例如,:-形式的扩展允许在变量未设置或为空时指定默认值

unset var
$ echo var: ${var:-default}
var: default

var=
$ echo var: ${var:-default}
var: default

现在,如果您省略冒号

unset var
$ echo var: ${var-default}
var: default

var=
$ echo var: ${var-default}
var:

因此,省略冒号会将测试从“未设置或空”更改为仅测试“未设置”。这适用于:-, :=, :?:+形式的参数扩展。

结果可能因版本而异

如果某些功能似乎不起作用,请检查您的 bash 版本

$ echo $BASH_VERSION
4.4.23(1)-release

Mitch Frazier 是 Emerson Electric Co. 的嵌入式系统程序员。自 2000 年代初以来,Mitch 一直是 Linux Journal 的贡献者和朋友。

加载 Disqus 评论