How to check if a variable is set in Bash?
如何知道bash中是否设置了变量?
例如,如何检查用户是否为函数提供了第一个参数?
1 2 3 | function a { # if $1 is set ? } |
(通常)正确的方法
1 | if [ -z ${var+x} ]; then echo"var is unset"; else echo"var is set to '$var'"; fi |
其中,
引号可以省略(因此我们可以称为
然而,尽管可以安全地省略引号,而且并非所有人都能立即察觉到(这个引号解释的第一作者,也是一个主要的bash编码人员,甚至不太清楚),但有时最好用
1 | if [ -z"$var" ]; then echo"var is blank"; else echo"var is set to '$var'"; fi |
这通常是错误的,因为它不区分未设置的变量和设置为空字符串的变量。也就是说,如果
在用户必须指定扩展名或附加属性列表的情况下,取消设置和"设置为空字符串"之间的区别非常重要,如果不指定扩展名或附加属性列表,则默认为非空值,而指定空字符串应使脚本使用空扩展名或附加属性列表。
不过,这种区别在每一种情况下都不一定是必要的。在这种情况下,
要检查非空/非零字符串变量,即如果设置了,请使用
1 | if [ -n"$1" ] |
它与
您可以这样使用它:
1 2 3 4 5 | if [ -n"$1" ]; then echo"You supplied the first parameter!" else echo"First parameter not supplied." fi |
以下是如何测试参数是未设置,还是为空("空")或设置为值:
1 2 3 4 5 6 7 8 9 10 11 12 13 | +--------------------+----------------------+-----------------+-----------------+ | | parameter | parameter | parameter | | | Set and Not Null | Set But Null | Unset | +--------------------+----------------------+-----------------+-----------------+ | ${parameter:-word} | substitute parameter | substitute word | substitute word | | ${parameter-word} | substitute parameter | substitute null | substitute word | | ${parameter:=word} | substitute parameter | assign word | assign word | | ${parameter=word} | substitute parameter | substitute null | assign word | | ${parameter:?word} | substitute parameter | error, exit | error, exit | | ${parameter?word} | substitute parameter | substitute null | error, exit | | ${parameter:+word} | substitute word | substitute null | substitute null | | ${parameter+word} | substitute word | substitute word | substitute null | +--------------------+----------------------+-----------------+-----------------+ |
源:posix:参数扩展:
In all cases shown with"substitute", the expression is replaced with the value shown. In all cases shown with"assign", parameter is assigned that value, which also replaces the expression.
虽然这里描述的大多数技术都是正确的,但是bash 4.2支持对变量(man bash)的存在进行实际测试,而不是测试变量的值。
1 2 3 4 5 6 7 8 9 10 | [[ -v foo ]]; echo $? # 1 foo=bar [[ -v foo ]]; echo $? # 0 foo="" [[ -v foo ]]; echo $? # 0 |
值得注意的是,这种方法在用于检查
有很多方法可以做到这一点,其中包括:
1 | if [ -z"$1" ] |
如果$1为空或未设置,则此操作成功
为了查看变量是否是非空的,我使用
1 | if [[ $var ]]; then ... # `$var' expands to a nonempty string |
如果变量未设置或为空,则进行相反的测试:
1 | if [[ ! $var ]]; then ... # `$var' expands to the empty string (set or not) |
为了查看是否设置了变量(空或非空),我使用
1 2 | if [[ ${var+x} ]]; then ... # `var' exists (empty or nonempty) if [[ ${1+x} ]]; then ... # Parameter 1 exists (empty or nonempty) |
如果变量未设置,则进行相反的测试:
1 2 | if [[ ! ${var+x} ]]; then ... # `var' is not set at all if [[ ! ${1+x} ]]; then ... # We were called with no arguments |
我总是发现另一个答案中的posix表比较慢,所以下面是我的看法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | +----------------------+------------+-----------------------+-----------------------+ | if VARIABLE is: | set | empty | unset | +----------------------+------------+-----------------------+-----------------------+ - | ${VARIABLE-default} | $VARIABLE | "" | "default" | = | ${VARIABLE=default} | $VARIABLE | "" | $(VARIABLE="default") | ? | ${VARIABLE?default} | $VARIABLE | "" | exit 127 | + | ${VARIABLE+default} |"default" | "default" | "" | +----------------------+------------+-----------------------+-----------------------+ :- | ${VARIABLE:-default} | $VARIABLE | "default" | "default" | := | ${VARIABLE:=default} | $VARIABLE | $(VARIABLE="default") | $(VARIABLE="default") | :? | ${VARIABLE:?default} | $VARIABLE | exit 127 | exit 127 | :+ | ${VARIABLE:+default} |"default" | "" | "" | +----------------------+------------+-----------------------+-----------------------+ |
请注意,每个组(有冒号和没有冒号)都有相同的设置和未设置案例,因此唯一不同的是如何处理空案例。
对于前面的冒号,空的和未设置的案例是相同的,所以我会尽可能使用这些案例(即使用
标题:
- set表示
VARIABLE 为非空(VARIABLE="something" ) - 空是指
VARIABLE 为空/空(VARIABLE="" ) - "未结算"是指
VARIABLE 不存在(unset VARIABLE )
价值观:
$VARIABLE 表示结果是变量的原值。"default" 表示结果是提供的替换字符串。"" 表示结果为空(空字符串)。exit 127 表示脚本停止执行,退出代码127。$(VARIABLE="default") 表示结果是变量的原始值,所提供的替换字符串被分配给变量以备将来使用。
在bash的现代版本上(我想是4.2或更高版本,我不确定),我会尝试以下方法:
1 2 3 4 5 6 7 8 9 | if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil then echo"Variable is unset" elif [ -z"$SOMEVARIABLE" ] then echo"Variable is set to an empty string" else echo"Variable is set to some string" fi |
1 2 3 4 5 | if ["$1" !="" ]; then echo \$1 is set else echo \$1 is not set fi |
尽管对于论点,通常最好测试$,我认为这是论点的数量。
1 2 3 4 5 | if [ $# -gt 0 ]; then echo \$1 is set else echo \$1 is not set fi |
如果未设置,您想退出
这对我有用。如果没有设置参数,我希望脚本退出并显示一条错误消息。
1 2 3 4 5 6 | #!/usr/bin/env bash set -o errexit # Get the value and empty validation check all in one VER="${1:?You must pass a version of the format 0.0.0 as the only argument}" |
当它运行时返回一个错误
1 2 | peek@peek:~$ ./setver.sh ./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument |
仅检查,不退出-空和未设置无效
如果只想检查值set=valid或unset/empty=invalid,请尝试此选项。
1 2 3 4 5 6 7 8 9 10 | TSET="good val" TEMPTY="" unset TUNSET if ["${TSET:-}" ]; then echo"VALID"; else echo"INVALID";fi # VALID if ["${TEMPTY:-}" ]; then echo"VALID"; else echo"INVALID";fi # INVALID if ["${TUNSET:-}" ]; then echo"VALID"; else echo"INVALID";fi # INVALID |
或者,即使是简短的测试;—)
1 2 3 | ["${TSET:-}" ] && echo"VALID" || echo"INVALID" ["${TEMPTY:-}" ] && echo"VALID" || echo"INVALID" ["${TUNSET:-}" ] && echo"VALID" || echo"INVALID" |
仅选中,不退出-仅空无效
这就是问题的答案。如果只想检查值set/empty=valid或unset=invalid,请使用此选项。
注意,..-1中的"1"不重要,它可以是任何东西(比如x)
1 2 3 4 5 6 7 8 9 10 | TSET="good val" TEMPTY="" unset TUNSET if ["${TSET+1}" ]; then echo"VALID"; else echo"INVALID";fi # VALID if ["${TEMPTY+1}" ]; then echo"VALID"; else echo"INVALID";fi # VALID if ["${TUNSET+1}" ]; then echo"VALID"; else echo"INVALID";fi # INVALID |
简短测试
1 2 3 | ["${TSET+1}" ] && echo"VALID" || echo"INVALID" ["${TEMPTY+1}" ] && echo"VALID" || echo"INVALID" ["${TUNSET+1}" ] && echo"VALID" || echo"INVALID" |
我将此答案献给@mklement0(评论),他要求我准确回答问题。
参考http://pubs.opengroup.org/onlinepubs/9699919799/utilities/v3_chap02.html tag_18_06_02
阅读
例如:
1 2 3 4 | function a { first_arg=${1-foo} # rest of the function } |
如果指定,则将
1 2 3 4 | function a { : ${1?a must take a single argument} # rest of the function } |
(注意使用
要检查变量是否设置为非空值,请使用
大多数情况下,最好将具有空值的变量视为未设置的变量。但如果需要,可以区分这两种情况:如果设置了
要检查参数是否已通过,测试
在bash中,您可以在
1 2 3 4 5 6 7 | #! /bin/bash -u if [[ ! -v SOMEVAR ]]; then SOMEVAR='hello' fi echo $SOMEVAR |
对于那些在使用
1 2 3 4 | if [ -z"${var-}" ]; then echo"Must provide var environment variable. Exiting...." exit 1 fi |
如果
注释
因为
只要您只处理bash中的命名变量,这个函数就应该总是告诉您是否设置了变量,即使它是一个空数组。
1 2 3 | is-variable-set() { declare -p $1 &>dev/null } |
为什么会这样
在bash中(至少早于3.0),如果
[ -n"$var" ] : This only checks if${var[0]} is nonempty. (In Bash,$var is the same as${var[0]} .)[ -n"${var+x}" ] : This only checks if${var[0]} is set.["${#var[@]}" != 0 ] : This only checks if at least one index of$var is set.
当这个方法在bash中失败时
这只适用于命名变量(包括
如果您的脚本有数组,并且您试图使其与尽可能多的shell兼容,那么考虑使用
如果您需要脚本与posix-sh兼容,那么就不能使用数组。没有阵列,
此函数取消设置变量
我跳过了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | is-var-set-after() { # Set var by passed expression. unset var eval"$1" # Run the tests, in increasing order of accuracy. [ -n"$var" ] # (index 0 of) var is nonempty nonempty=$? [ -n"${var+x}" ] # (index 0 of) var is set, maybe empty plus=$? ["${#var[@]}" != 0 ] # var has at least one index set, maybe empty count=$? declare -p var &>/dev/null # var has been declared (any type) declared=$? # Show test results. printf '%30s: %2s %2s %2s %2s '"$1" $nonempty $plus $count $declared } |
测试用例代码
注意,如果变量没有声明为关联数组,那么测试结果可能是意外的,因为bash将非数字数组索引视为"0"。此外,关联数组仅在bash 4.0+中有效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # Header. printf '%30s: %2s %2s %2s %2s '"test" '-n' '+x' '#@' '-p' # First 5 tests: Equivalent to setting 'var=foo' because index 0 of an # indexed array is also the nonindexed value, and non-numerical # indices in an array not declared as associative are the same as # index 0. is-var-set-after"var=foo" # 0 0 0 0 is-var-set-after"var=(foo)" # 0 0 0 0 is-var-set-after"var=([0]=foo)" # 0 0 0 0 is-var-set-after"var=([x]=foo)" # 0 0 0 0 is-var-set-after"var=([y]=bar [x]=foo)" # 0 0 0 0 # '[ -n"$var" ]' fails when var is empty. is-var-set-after"var=''" # 1 0 0 0 is-var-set-after"var=([0]='')" # 1 0 0 0 # Indices other than 0 are not detected by '[ -n"$var" ]' or by # '[ -n"${var+x}" ]'. is-var-set-after"var=([1]='')" # 1 1 0 0 is-var-set-after"var=([1]=foo)" # 1 1 0 0 is-var-set-after"declare -A var; var=([x]=foo)" # 1 1 0 0 # Empty arrays are only detected by 'declare -p'. is-var-set-after"var=()" # 1 1 1 0 is-var-set-after"declare -a var" # 1 1 1 0 is-var-set-after"declare -A var" # 1 1 1 0 # If 'var' is unset, then it even fails the 'declare -p var' test. is-var-set-after"unset var" # 1 1 1 1 |
测试输出
标题行中的测试助记符分别对应于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | test: -n +x #@ -p var=foo: 0 0 0 0 var=(foo): 0 0 0 0 var=([0]=foo): 0 0 0 0 var=([x]=foo): 0 0 0 0 var=([y]=bar [x]=foo): 0 0 0 0 var='': 1 0 0 0 var=([0]=''): 1 0 0 0 var=([1]=''): 1 1 0 0 var=([1]=foo): 1 1 0 0 declare -A var; var=([x]=foo): 1 1 0 0 var=(): 1 1 1 0 declare -a var: 1 1 1 0 declare -A var: 1 1 1 0 unset var: 1 1 1 1 |
总结
declare -p var &>/dev/null is (100%?) reliable for testing named variables in Bash since at least 3.0.[ -n"${var+x}" ] is reliable in POSIX compliant situations, but cannot handle arrays.- Other tests exist for checking if a variable is nonempty, and for checking for declared variables in other shells. But these tests are suited for neither Bash nor POSIX scripts.
你可以做到:
1 2 3 4 5 | function a { if [ ! -z"$1" ]; then echo '$1 is set' fi } |
当启用bash选项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | is_var_defined() { if [ $# -ne 1 ] then echo"Expected exactly one argument: variable name as string, e.g., 'my_var'" exit 1 fi # Tricky. Since Bash option 'set -u' may be enabled, we cannot directly test if a variable # is defined with this construct: [ ! -z"$var" ]. Instead, we must use default value # substitution with this construct: [ ! -z"${var:-}" ]. Normally, a default value follows the # operator ':-', but here we leave it blank for empty (null) string. Finally, we need to # substitute the text from $1 as 'var'. This is not allowed directly in Bash with this # construct: [ ! -z"${$1:-}" ]. We need to use indirection with eval operator. # Example: $1="var" # Expansion for eval operator:"[ ! -z \${$1:-} ]" ->"[ ! -z \${var:-} ]" # Code execute: [ ! -z ${var:-} ] eval"[ ! -z \${$1:-} ]" return $? # Pedantic. } |
相关:在bash中,如何测试变量是否以"-u"模式定义
使用
1 2 3 4 5 | $ set='' $ [[ -z"$set" ]] && echo"Set" || echo"Unset" Unset $ [[ -z"$unset" ]] && echo"Set" || echo"Unset" Unset |
最好根据变量类型进行检查:env变量、参数或正则变量。
对于env变量:
1 | [[ $(env | grep"varname=" | wc -l) -eq 1 ]] && echo"Set" || echo"Unset" |
对于参数(例如,检查参数
1 | [[ $# -ge 5 ]] && echo"Set" || echo"Unset" |
对于常规变量(使用辅助函数,以优雅的方式执行):
1 2 3 4 | function declare_var { declare -p"$1" &> /dev/null } declare_var"var_name" && echo"Set" || echo"Unset" |
笔记:
$# : gives you the number of positional parameters.declare -p : gives you the definition of the variable passed as a parameter. If it exists, returns 0, if not, returns 1 and prints an error message.&> /dev/null : suppresses output fromdeclare -p without affecting its return code.
在shell中,可以使用
一个简单的一行程序,用于设置默认的
1 2 | [[ -z"$MY_VAR" ]] && MY_VAR="default" [[ -z"$MY_VAR" ]] && MY_VAR="default" || echo"Variable already set." |
我最喜欢的方式是:
1 2 3 4 5 6 | $var=10 $if ! ${var+false};then echo"is set";else echo"NOT set";fi is set $unset var $if ! ${var+false};then echo"is set";else echo"NOT set";fi NOT set |
因此,基本上,如果设置了一个变量,它将成为"对结果
如果未设置,则将变成"对生成的
如果您想检查
1 2 3 4 5 6 | if [[ $1 ="" ]] then echo '$1 is blank' else echo '$1 is filled up' fi |
为什么这一切?
更新:还可以计算参数中的字符数。
1 2 3 4 5 6 | if [ ${#1} = 0 ] then echo '$1 is blank' else echo '$1 is filled up' fi |
1 2 3 4 5 6 7 8 9 | if [[ ${1:+isset} ]] then echo"It was set and not null.">&2 else echo"It was not set or it was null.">&2 fi if [[ ${1+isset} ]] then echo"It was set but might be null.">&2 else echo"It was was not set.">&2 fi |
1 | [[ $foo ]] |
或
1 | (( ${#foo} )) |
或
1 | let ${#foo} |
或
1 | declare -p foo |
这是我每天使用的:
1 2 3 4 5 6 7 8 | # # Check if a variable is set # param1 name of the variable # function is_set() { [[ -n"${1}" ]] && test -n"$(eval"echo"\${${1}+x}"")" } |
这在Linux和Solaris下非常适用,直到bash 3.0。
1 2 3 4 5 6 7 8 9 | bash-3.00$ myvar="TEST" bash-3.00$ is_set myvar ; echo $? 0 bash-3.00$ mavar="" bash-3.00$ is_set myvar ; echo $? 0 bash-3.00$ unset myvar bash-3.00$ is_set myvar ; echo $? 1 |
1 | if [[ ${!xx[@]} ]] ; then echo xx is defined; fi |
我喜欢辅助功能来隐藏bash的原始细节。在这种情况下,这样做会增加更多(隐藏的)粗糙度:
1 2 3 4 5 6 7 | # The first ! negates the result (can't use -n to achieve this) # the second ! expands the content of varname (can't do ${$varname}) function IsDeclared_Tricky { local varname="$1" ! [ -z ${!varname+x} ] } |
因为我第一次在这个实现中有错误(受到Jens和Lionel的回答的启发),所以我想出了一个不同的解决方案:
1 2 3 4 5 | # Ask for the properties of the variable - fails if not declared function IsDeclared() { declare -p $1 &>/dev/null } |
我发现它更直接,更害羞,更容易理解/记忆。测试用例显示它是等效的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function main() { declare -i xyz local foo local bar= local baz='' IsDeclared_Tricky xyz; echo"IsDeclared_Tricky xyz: $?" IsDeclared_Tricky foo; echo"IsDeclared_Tricky foo: $?" IsDeclared_Tricky bar; echo"IsDeclared_Tricky bar: $?" IsDeclared_Tricky baz; echo"IsDeclared_Tricky baz: $?" IsDeclared xyz; echo"IsDeclared xyz: $?" IsDeclared foo; echo"IsDeclared foo: $?" IsDeclared bar; echo"IsDeclared bar: $?" IsDeclared baz; echo"IsDeclared baz: $?" } main |
测试用例还显示
IsDeclared_Tricky xyz: 1
IsDeclared_Tricky foo: 1
IsDeclared_Tricky bar: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
IsDeclared foo: 1
IsDeclared bar: 0
IsDeclared baz: 0
奖金:使用
我主要使用这个测试以某种"优雅"和安全的方式(几乎类似于一个接口…)为函数提供(和返回)参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #auxiliary functions function die() { echo"Error: $1"; exit 1 } function assertVariableDeclared() { IsDeclared"$1" || die"variable not declared: $1" } function expectVariables() { while (( $# > 0 )); do assertVariableDeclared $1; shift done } # actual example function exampleFunction() { expectVariables inputStr outputStr outputStr="$inputStr world!" } function bonus() { local inputStr='Hello' local outputStr= # remove this to trigger error exampleFunction echo $outputStr } bonus |
如果用all调用,则需要声明变量:
Hello world!
其他:
Error: variable not declared: outputStr
我总是使用这个代码,因为任何第一次看到代码的人都很容易理解它:
1 2 3 4 | if ["$variable" ="" ] then echo"Variable X is empty" fi |
如果想检查是否为空;
1 2 3 4 | if [ !"$variable" ="" ] then echo"Variable X is not empty" fi |
就是这样。
如果要测试变量是绑定的还是未绑定的,即使在打开nounset选项之后,这也能很好地工作:
1 2 3 4 5 6 7 | set -o noun set if printenv variableName >/dev/null; then # variable is bound to a value else # variable is unbound fi |
用于检查变量是否已声明/未设置的函数包括空的EDOCX1[0]
以下函数测试给定名称是否作为变量存在
1 2 3 4 5 6 7 8 9 10 | # The first parameter needs to be the name of the variable to be checked. # (See example below) var_is_declared() { { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;} } var_is_unset() { { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} } |
- 通过首先测试变量是否已设置(un),如果不需要,可以避免调用declare。
- 但是,如果
$1 包含空$array=() 的名称,则调用declare将确保获得正确的结果。 - 从未有太多数据传递给/dev/null,因为只有在变量未设置或数组为空时才调用declare。
该功能将在以下条件下进行测试:
1
2
3
4
5
6
7
8
9
10
11
12
13 a; # is not declared
a=; # is declared
a="foo"; # is declared
a=(); # is declared
a=(""); # is declared
unset a; # is not declared
a; # is unset
a=; # is not unset
a="foo"; # is not unset
a=(); # is not unset
a=(""); # is not unset
unset a; # is unset
.
For more details
and a test script see my answer to the question"How do I check if a variable exists in bash?".
Remark: The similar usage of
declare -p , as it is also shown by Peregring-lk's answer, is truly coincidental. Otherwise I would of course have credited it!
检查是否设置了变量
1 | var=""; [[ $var ]] && echo"set" || echo"not set" |
1 2 3 4 | case"$1" in "") echo"blank";; *) echo"set" esac |