在Bash中用单个命令为shell变量分配默认值

在Bash中用单个命令为shell变量分配默认值

技术背景

在Bash脚本编程中,经常需要为变量分配默认值,以处理变量未设置或为空的情况。Bash提供了参数扩展机制,可以方便地实现这一功能。

实现步骤

获取分配的值或默认值

可以使用Bash参数扩展 ${parameter:-default} 来获取变量的分配值,如果变量未设置或为空,则使用默认值。例如:

1
2
FOO="${VARIABLE:-default}"  # 如果VARIABLE未设置或为空,FOO将被分配'default'值
# VARIABLE的值保持不变

分配默认值并赋值给变量

使用 ${parameter:=default} 可以在变量未设置或为空时,将默认值赋给变量,并将该值分配给另一个变量。例如:

1
2
FOO="${VARIABLE:=default}"  # 如果VARIABLE未设置或为空,将其值设置为'default'
# 然后该值将被分配给FOO

处理命令行参数

对于命令行参数,可以使用 ${n:-default} 来分配默认值。例如:

1
VARIABLE="${1:-$DEFAULTVALUE}"

这将把传递给脚本的第一个参数的值赋给 VARIABLE,如果没有传递该参数,则使用 DEFAULTVALUE 的值。

链式默认值

可以链式使用默认值,例如:

1
DOCKER_LABEL=${GIT_TAG:-${GIT_COMMIT_AND_DATE:-latest}}

如果 $GIT_TAG 不存在,则使用 $GIT_COMMIT_AND_DATE 的值;如果 $GIT_COMMIT_AND_DATE 也不存在,则使用 latest

核心代码

参数扩展示例

1
2
3
4
5
6
7
8
9
10
11
# 获取分配的值或默认值
FOO="${VARIABLE:-default}"

# 分配默认值并赋值给变量
FOO="${VARIABLE:=default}"

# 命令行参数处理
VARIABLE="${1:-$DEFAULTVALUE}"

# 链式默认值
DOCKER_LABEL=${GIT_TAG:-${GIT_COMMIT_AND_DATE:-latest}}

错误信息提示

1
USERNAME=${1:?"Specify a username"}

如果第一个参数未设置,将显示错误信息并以代码1退出。

条件赋值示例

1
2
3
4
5
6
7
(( x > 50 )) && o="UPPER" || o="LOWER"
[[ $x -ge 50 ]] && o="UPPER" || o="LOWER"
o="$( (( x > 50 )) && echo "UPPER" || echo "LOWER" )"
(( x > 50 )) && o="UPPER"
: "${o:=LOWER}"
o="LOWER"
(( x > 50 )) && o="UPPER"

最佳实践

使用总结表

变量在shell脚本中有三种状态:已分配值、空字符串和未设置。以下是参数扩展表达式的总结表:

表达式x已设置且不为空x设置为空字符串x未设置
${x:-default_value}$xdefault_valuedefault_value
${x-default_value}$x$x (空字符串)default_value
${x:=default_value}$xdefault_valuedefault_value
${x=default_value}$x$x (空字符串)default_value
${x:?error message}$xerror messageerror message
${x:+alternate_value}alternate_value$x (空字符串)null

使用Bash单行命令测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# bash one liner                                # output 
# -------------- ------
x="foo" && echo "${x:-bar} (x = $x)" # foo (x = foo)
x="" && echo "${x:-bar} (x = $x)" # bar (x = )
unset x && echo "${x:-bar} (x = $x)" # bar (x = )
x="foo" && echo "${x-bar} (x = $x)" # foo (x = foo)
x="" && echo "${x-bar} (x = $x)" # (x = )
unset x && echo "${x-bar} (x = $x)" # bar (x = )
x="foo" && echo "${x:=bar} (x = $x)" # foo (x = foo)
x="" && echo "${x:=bar} (x = $x)" # bar (x = bar)
unset x && echo "${x:=bar} (x = $x)" # bar (x = bar)
x="foo" && echo "${x=bar} (x = $x)" # foo (x = foo)
x="" && echo "${x=bar} (x = $x)" # (x = )
unset x && echo "${x=bar} (x = $x)" # bar (x = bar)
x="foo" && echo "(x = $x)" && echo "${x:?error message}" # (x = foo) foo
x="" && echo "(x = $x)" && echo "${x:?error message}" # (x = ) bash: x: error message
unset x && echo "(x = $x)" && echo "${x:?error message}" # (x = ) bash: x: error message
x="foo" && echo "${x:+bar} (x = $x)" # bar (x = foo)
x="" && echo "${x:+bar} (x = $x)" # (x = )
unset x && echo "${x:+bar} (x = $x)" # (x = )

常见问题

参数不能为表达式

参数扩展中,参数(左侧)不能是表达式。如果需要根据表达式进行赋值,需要使用其他方式。

冒号的作用

在参数扩展中,冒号的存在与否会影响测试条件。如果包含冒号,运算符会测试参数的存在性及其值是否不为空;如果省略冒号,运算符仅测试参数的存在性。例如:

1
2
3
4
# 包含冒号,测试存在性和值不为空
FOO="${VARIABLE:-default}"
# 省略冒号,仅测试存在性
FOO="${VARIABLE-default}"

在Bash中用单个命令为shell变量分配默认值
https://119291.xyz/posts/assigning-default-values-to-shell-variables-in-bash/
作者
ww
发布于
2025年7月17日
许可协议