Bourne Shell 脚本/变量扩展
在 环境 模块中,我们介绍了环境变量的概念,它是一种通用的方法来存储小块数据。在本模块中,我们将深入探讨使用这些变量:'变量扩展'、'参数替换'或简称为 '替换'。
使用变量被称为替换的原因是,shell 会将对任何变量的引用替换为它的值。这在评估命令行时完成,这意味着变量替换发生在命令实际执行之前。
使用变量的最简单方法是我们已经见过的,在变量名前面加一个 '$'。例如
当然,一旦替换完成,结果仍然只是变量中的文本。对该文本的解释仍然由运行的程序完成。例如
基本变量扩展已经非常灵活。你可以像上面描述的那样使用它,但也可以使用变量来创建更长的字符串。例如,如果你想将应用程序的日志目录设置为你主目录中的 "log" 目录,你可以这样填写设置
$HOME/log
如果你要更频繁地使用该设置,你可能想创建你自己的变量,例如
LOGDIR=$HOME/log
当然,如果你想为不同的程序创建特定的日志子目录,那么 Wyxliz 应用程序的日志将位于目录
$LOGDIR/Wyxliz/
Bourne Shell 有许多不同的变量替换语法,每种语法都有其含义和用途。在本节中,我们将研究这些语法。
我们已经详细讨论了基本变量替换:你定义一个变量,在它前面加上一个 '$',shell 将用变量的值替换该变量。现在你可能已经厌倦了听到它。
但我们还没有讨论基本变量替换中你可能会遇到的一个情况。考虑以下情况
那么哪里出错了呢?显然,shell 没有为 ANIMAL 变量替换任何东西,但为什么呢?因为加上 's' 后,shell 认为我们正在请求不存在的 ANIMALs 变量。但这究竟是怎么回事呢?我们之前已经在字符串中间使用过变量(例如 '/home/ANIMAL/logs')。但 's' 不是 '/':'s' 可以是变量名称的有效部分,因此 shell 无法区分它们。在必须明确将变量与其他文本分隔开的情况下,可以使用大括号
两种情况(带括号和不带括号)都属于基本变量替换,规则完全相同。只需记住不要在括号和变量名称之间留任何空格。
由于变量可以为空,因此你经常会在脚本中编写代码来检查强制性变量是否确实具有值。但在可选变量的情况下,通常更方便的是不检查,而是使用默认值来代替未定义的变量。这种情况实际上非常普遍,以至于 Bourne Shell 为此定义了一种特殊的语法:连字符。由于连字符对 shell 也有其他含义,因此你必须将其与大括号结合使用 - 最终结果如下
而 default 是在 varname 未定义时使用的值
同样,不要在括号和其他文本之间留任何空格。使用这种语法的示例如下
与之对比
没有冒号,变量只有在未定义时才会被替换
$ VAR=value EMPTY_VAR=
$ echo ${VAR:-empty}, ${EMPTY_VAR:-empty}, ${ABSENCE_VAR:-empty}
value, empty, empty
$ echo ${VAR-empty}, ${EMPTY_VAR-empty}, ${ABSENCE_VAR-empty}
value, , empty
作为默认值的扩展,有一种语法不仅提供了默认值,而且同时将默认值赋予未设置的变量。它看起来像这样
而 default 是在 varname 未定义时使用的并被赋值的值
像往常一样,避免在括号之间留空格。以下示例演示了这种语法的工作方式
$ echo $NEWVAR
$ echo ${NEWVAR:=newval}
newval
$ echo $NEWVAR
newval
没有冒号,变量只有在未定义时才会被赋值
$ echo $NEWVAR
$ EMPTY_VAR=
$ unset ABSENCE_VAR
$ echo ${EMPTY_VAR:=empty}, ${ABSENCE_VAR:=empty}
empty, empty
$ echo ${EMPTY_VAR}, ${ABSENCE_VAR}
empty, empty
$ EMPTY_VAR=
$ unset ABSENCE_VAR
$ echo ${EMPTY_VAR=empty}, ${ABSENCE_VAR=empty}
, empty
$ echo ${EMPTY_VAR}, ${ABSENCE_VAR}
, empty
这种替换是一种快速测试,用于检查变量是否已定义(这通常是它的用途)。它有点类似于默认值语法的反向操作,看起来像这样
而 substitute 是在 varname 定义时使用的值
如果变量已定义,则此语法返回替换值。这乍一看似乎有悖常理,特别是如果你问如果变量未定义会返回什么 - 并了解到返回的值为空。以下是一个示例
$ echo ${NEWVAR:+newval}
$ NEWVAR=oldval
$ echo ${NEWVAR:+newval}
newval
那么,这种表示法有什么用呢?它经常用在必须检查许多变量是否已设置的脚本中。在这种情况下,变量具有值意味着已激活某个选项,因此你感兴趣的是知道变量有值,而不是该值是什么。它看起来像这样(伪代码,这在 shell 中实际上不起作用)
没有冒号,变量即使为空也会被替换
$ VAR=value EMPTY_VAR=
$ echo ${VAR:+newvalue}, ${EMPTY_VAR:+newvalue}, ${ABSENCE_VAR:+newvalue}
newvalue, ,
$ echo ${VAR+newvalue}, ${EMPTY_VAR+newvalue}, ${ABSENCE_VAR+newvalue}
newvalue, newvalue,
最后一种语法是一种调试检查,用于检查变量是否已设置。它看起来像这样
而 message 是在 varname 未定义时打印的内容
使用此语法,如果变量已定义,则一切正常。否则,将打印消息,并且命令或脚本将以非零退出状态退出。或者,如果没有消息,将打印文本 "参数为空或未设置"。
你可以使用此语法来检查脚本的强制性变量是否已设置,并在它们未设置时打印错误消息。
$ echo ${SOMEVAR:?has not been set}
-sh: SOMEVAR: has not been set
$ echo ${SOMEVAR:?}
-sh: SOMEVAR: parameter null or not set
带冒号,变量也会被检查是否为空
$ EMPTY_VAR=
$ echo ${EMPTY_VAR:?has not been set or empty}
-sh: EMPTY_VAR: has not been set or empty
$ echo ${ABSENCE_VAR:?has not been set or empty}
-sh: ABSENCE_VAR: has not been set or empty
$ echo ${EMPTY_VAR?has not been set or empty}
$ echo ${ABSENCE_VAR?has not been set or empty}
-sh: ABSENCE_VAR: has not been set or empty