跳转到内容

Bourne Shell 脚本/变量扩展

来自 Wikibooks,开放世界中的开放书籍

环境 模块中,我们介绍了环境变量的概念,它是一种通用的方法来存储小块数据。在本模块中,我们将深入探讨使用这些变量:'变量扩展'、'参数替换'或简称为 '替换'。

使用变量被称为替换的原因是,shell 会将对任何变量的引用替换为它的值。这在评估命令行时完成,这意味着变量替换发生在命令实际执行之前

使用变量的最简单方法是我们已经见过的,在变量名前面加一个 '$'。例如

简单使用变量

代码:

$ USER=JoeSixpack
$ echo $USER

输出:

JoeSixpack
在执行 echo 命令之前,值 JoeSixpack 被替换为 $USER。

当然,一旦替换完成,结果仍然只是变量中的文本。对该文本的解释仍然由运行的程序完成。例如

变量不能创造奇迹

代码:

$ USER=JoeSixpack
$ ls $USER

输出:

ls: 无法访问 JoeSixpack: 没有此类文件或目录
仅仅因为文本来自变量,并不意味着文件存在。

基本变量扩展已经非常灵活。你可以像上面描述的那样使用它,但也可以使用变量来创建更长的字符串。例如,如果你想将应用程序的日志目录设置为你主目录中的 "log" 目录,你可以这样填写设置

$HOME/log

如果你要更频繁地使用该设置,你可能想创建你自己的变量,例如

LOGDIR=$HOME/log

当然,如果你想为不同的程序创建特定的日志子目录,那么 Wyxliz 应用程序的日志将位于目录

$LOGDIR/Wyxliz/

替换形式

[编辑 | 编辑源代码]

Bourne Shell 有许多不同的变量替换语法,每种语法都有其含义和用途。在本节中,我们将研究这些语法。

基本变量替换

[编辑 | 编辑源代码]

我们已经详细讨论了基本变量替换:你定义一个变量,在它前面加上一个 '$',shell 将用变量的值替换该变量。现在你可能已经厌倦了听到它。

但我们还没有讨论基本变量替换中你可能会遇到的一个情况。考虑以下情况

将一些文本添加到变量的值

代码:

$ ANIMAL=duck
$ echo One $ANIMAL, two $ANIMALs

输出:

一只鸭子,两只
嗯...... 我们好像漏了什么......

那么哪里出错了呢?显然,shell 没有为 ANIMAL 变量替换任何东西,但为什么呢?因为加上 's' 后,shell 认为我们正在请求不存在的 ANIMALs 变量。但这究竟是怎么回事呢?我们之前已经在字符串中间使用过变量(例如 '/home/ANIMAL/logs')。但 's' 不是 '/':'s' 可以是变量名称的有效部分,因此 shell 无法区分它们。在必须明确将变量与其他文本分隔开的情况下,可以使用大括号

将一些文本添加到变量的值,再来一次

代码:

$ ANIMAL=duck
$ echo One $ANIMAL, two ${ANIMAL}s

输出:

一只鸭子,两只鸭子
这样就好多了!

两种情况(带括号和不带括号)都属于基本变量替换,规则完全相同。只需记住不要在括号和变量名称之间留任何空格。

使用默认值的替换

[编辑 | 编辑源代码]

由于变量可以为空,因此你经常会在脚本中编写代码来检查强制性变量是否确实具有值。但在可选变量的情况下,通常更方便的是不检查,而是使用默认值来代替未定义的变量。这种情况实际上非常普遍,以至于 Bourne Shell 为此定义了一种特殊的语法:连字符。由于连字符对 shell 也有其他含义,因此你必须将其与大括号结合使用 - 最终结果如下

${varname[:]-default}
* 其中 varname 是变量的名称
default 是在 varname 未定义时使用的值

同样,不要在括号和其他文本之间留任何空格。使用这种语法的示例如下

默认值

代码:

$ THIS_ONE_SET=Hello
$ echo $THIS_ONE_SET ${THIS_ONE_NOT:-World}

输出:

你好,世界

与之对比

不需要默认值

代码:

$ TEXT=aaaaaahhhhhhhh
$ echo Say ${TEXT:-bbbbbbbbbb}

输出:

啊啊啊啊啊啊啊

没有冒号,变量只有在未定义时才会被替换

带冒号和不带冒号的默认值
$ 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


使用默认赋值的替换

[编辑 | 编辑源代码]

作为默认值的扩展,有一种语法不仅提供了默认值,而且同时将默认值赋予未设置的变量。它看起来像这样

${varname[:]=default}
* 其中 varname 是变量的名称
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


实际值的替换

[编辑 | 编辑源代码]

这种替换是一种快速测试,用于检查变量是否已定义(这通常是它的用途)。它有点类似于默认值语法的反向操作,看起来像这样

${varname[:]+substitute}
* 其中 varname 是变量的名称
substitute 是在 varname 定义时使用的值

如果变量定义,则此语法返回替换值。这乍一看似乎有悖常理,特别是如果你问如果变量定义会返回什么 - 并了解到返回的值为空。以下是一个示例

实际值替换
$ echo ${NEWVAR:+newval}

$ NEWVAR=oldval
$ echo ${NEWVAR:+newval}
newval


那么,这种表示法有什么用呢?它经常用在必须检查许多变量是否已设置的脚本中。在这种情况下,变量具有值意味着已激活某个选项,因此你感兴趣的是知道变量值,而不是该值是什么。它看起来像这样(伪代码,这在 shell 中实际上不起作用)

默认值赋值
if ${SPECIFIC_OPTION_VAR:+optionset} == optionset then ...


没有冒号,变量即使为空也会被替换

默认值赋值
$ 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,


使用值检查的替换

[编辑 | 编辑源代码]

最后一种语法是一种调试检查,用于检查变量是否已设置。它看起来像这样

${varname[:]?message}
* 其中 varname 是变量的名称
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


下一页: 控制流 | 上一页: 环境
首页: Bourne Shell 脚本
华夏公益教科书