跳转到内容

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 无法区分它们。在您必须明确地将变量与其他文本分隔开的情况下,可以使用大括号

向变量的值添加一些文本,第 II 部分

代码:

$ 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}

输出:

Hello 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 是变量的名称
如果varname没有定义,则会打印message

使用这种语法,如果变量已定义,一切正常。否则,将打印消息,并且命令或脚本以非零退出状态退出。或者,如果没有消息,则会打印文本“参数为空或未设置”。

您可以使用这种语法来检查脚本的必需变量是否已设置,并在未设置时打印错误消息。

默认值赋值
$ 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 脚本
华夏公益教科书