如果我想检查空字符串,我会这样做
[ -z $mystr ]
但是如果我想要检查变量是否被定义了呢?在Bash脚本中有没有区别呢?
我认为你需要的答案已经在Vinko的answer中暗示(如果没有明确说明),尽管它并没有简单地表述出来。要区分VAR是设置为空还是未设置,您可以使用:
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
您可以通过以下方式将第二行的两个测试组合成一个测试:
if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
-a
'结合使用,并建议使用单独的简单测试与&&
组合。我没有遇到过存在问题的系统;这并不意味着它们以前不存在(但即使它们在遥远的过去不那么罕见,如今也可能极其罕见)。test
或[
命令和条件表达式。
最近我收到了一封关于这个答案的邮件,邮件中提到:
公平的问题 - 答案是“不,你更简单的替代方案并没有做同样的事情”。You use two tests, and I understand the second one well, but not the first one. More precisely I don't understand the need for variable expansion
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
Wouldn't this accomplish the same?
if [ -z "${VAR}" ]; then echo "VAR is not set at all"; fi
VAR=
你的测试会显示“VAR根本没有设置”,但我的测试将会(通过暗示,因为它没有输出任何内容)显示“VAR已经设置,但其值可能为空”。试试这个脚本:
(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo "JL:1 VAR is not set at all"; fi
if [ -z "${VAR}" ]; then echo "MP:1 VAR is not set at all"; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo "JL:2 VAR is not set at all"; fi
if [ -z "${VAR}" ]; then echo "MP:2 VAR is not set at all"; fi
)
JL:1 VAR根本没有被设置 MP:1 VAR根本没有被设置 MP:2 VAR根本没有被设置在第二组测试中,变量被设置了,但是它被设置为空值。这就是
${VAR=value}
和${VAR:=value}
的区别所在。同样适用于${VAR-value}
和${VAR:-value}
、${VAR+value}
和${VAR:+value}
等等。
正如Gili在他的answer中指出的那样,如果你使用set -o nounset
选项运行bash
,那么上面的基本答案将失败,并显示unbound variable
。解决方法很简单:
if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi
或者您可以使用set +u
取消set -o nounset
选项(set -u
等同于set -o nounset
),这样也可以。
${+}
和 ${-}
的程序员来说,这可能不清楚,但如果要成为一个熟练的 shell 用户,熟悉这些结构是必要的。 - William Pursellset -o nounset
,请查看https://dev59.com/R3VC5IYBdhLWcg3woSxW#20003892以实现此功能。 - Gili[ -v VAR ]
"方法。 - will~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~>
-z也适用于未定义的变量。为了区分已定义和未定义的变量,可以使用这里列出的内容或者这里提供的更清晰的解释。
最干净的方法是使用扩展,就像这些示例中所示。要获取所有选项,请查看手册中的参数扩展部分。
替代单词:
~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED
默认值:
~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED
当然,你会不同地使用它们,用你想要的值而不是 "默认值",并直接使用扩展(如果适用)。
高级Bash脚本指南,10.2. 参数替换:
如果你想要根据变量$mystr是否被定义来构建程序逻辑,你可以按照以下方式进行:
isdefined=0
${mystr+ export isdefined=1}
现在,如果isdefined=0,则变量未定义,如果isdefined=1,则变量已定义。
这种检查变量的方式比以前的答案更好,因为它更优雅、可读,并且如果您的Bash shell配置为在使用未定义变量时出错(set -u),则脚本将过早终止。
其他有用的东西:
如果$mystr未定义,则将默认值7分配给$mystr,并保持其不变:
mystr=${mystr- 7}
如果变量未定义,打印错误消息并退出函数:
: ${mystr? not defined}
var= ; varname=var ; : ${!varname?not defined}
,而这个终止:varname=var ; : ${!varname?not defined}
。但是使用 set -u
是一个好习惯,它可以更轻松地完成相同的任务。 - ceving测试摘要。
[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set" # may or may not be empty
[ -n "${var+x}" ] && echo "var is set" # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"
${var+x}
只有在变量名称允许包含空格时才是必要的。 - Anne van Rossum[
获取正确的结果是必需的。如果 var
未设置或为空,则 [ -n $var ]
简化为 [ -n ]
,其退出状态为0,而 [ -n "$var" ]
具有预期(和正确的)退出状态1。 - chepner当使用“set -o nounset”时,如何在bash中测试变量是否设置包含更好的答案(更易读且适用于启用了set -o nounset
)。它的大致工作方式如下:
if [ -n "${VAR-}" ]; then
echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
echo "VAR is set, but empty"
else
echo "VAR is not set"
fi
检查变量是否已定义的明确方法如下:
[ -v mystr ]
test
运算符。我不知道它是何时添加的,但它不在苹果版本的bash
(基于bash
3.2.51)中,所以它可能是4.x版本的功能。 - Jonathan LefflerGNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
上不起作用。错误是 -bash: [: -v: unary operator expected
。根据这里的评论,它需要至少bash 4.2才能工作。 - Asclepius$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1
foo
未设置时,因此您可以使用字符串条件来检查它。$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0
应该在任何Bash 3.0或更高版本中可用。
不想再多说这辆自行车了,但是想要补充一下
shopt -s -o nounset
在脚本的顶部可以添加一些内容,如果变量在脚本中没有被声明,它将会出现错误。
你会看到的消息是未绑定的变量,但正如其他人提到的那样,它不会捕捉空字符串或null值。
为了确保任何单个值不为空,我们可以在扩展变量时测试变量,使用${mystr:?}
,也称为美元符号扩展,这将出现错误参数为空或未设置
。
Bash参考手册是关于Bash的权威信息来源。
这里有一个测试变量是否存在的示例:
if [ -z "$PS1" ]; then
echo This shell is not interactive
else
echo This shell is interactive
fi
(来自6.3.2章节。)
请注意,在开放的[
和]
之后以及之前的空格是不可选的。
Vim 用户小技巧
我有一个脚本,其中有几个声明如下:
export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
但我希望他们遵从任何现有的价值观。所以,我将它们改写成了这样:
if [ -z "$VARIABLE_NAME" ]; then
export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi
s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r export \1=\2\rfi\r/gc
这可以通过在可视化选择相关行,然后键入:
来应用。命令栏会自动填充为:'<,'>
。粘贴上述命令并按下Enter。
VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com
Windows用户可能需要不同的行尾。
这是我认为更清晰的检查变量是否已定义的方法:
var_defined() {
local var_name=$1
set | grep "^${var_name}=" 1>/dev/null
return $?
}
使用方法如下:
if var_defined foo; then
echo "foo is defined"
else
echo "foo is not defined"
fi
grep
真的很糟糕。请注意,bash
支持 ${!var_name}
作为获取变量名指定的变量值的一种方式,因此 name=value; value=1; echo ${name} ${!name}
会输出 value 1
。 - Jonathan Leffler
[ -n "${VAR+x}"] && echo not null
怎么看? - Lekensteyn[ -z ]
而不是[ -z "" ]
;如果有空格,则会变成[ -z "my" "test" ]
而不是[ -z my test ]
;而如果变量是[ -z * ]
,则*
将被替换为目录中文件的名称。 - Charles Duffy