如何检查Bash中是否设置了变量?

时间:2010-08-30 14:54:38

标签: bash shell variables

如何知道Bash中是否设置了变量?

例如,如何检查用户是否将第一个参数提供给函数?

function a {
    # if $1 is set ?
}

37 个答案:

答案 0 :(得分:1931)

(通常)正确的方式

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

其中${var+x}parameter expansion,如果var未设置,则评估为空,否则替换字符串x

引言弃儿

引号可以省略(因此我们可以说${var+x}代替"${var+x}"),因为这种语法&使用保证这只会扩展到不需要引号的东西(因为它扩展到x(不包含任何分词,所以它不需要引号),或者什么都不扩展(导致[ -z ],方便地评估[ -z "" ]所做的相同值(真))。

然而,尽管可以安全地省略引号,并且它并不是立即显而易见的(对the first author of this quotes explanation来说,即使是主要的Bash编码器也不是很明显),有时候写出来更好一些。引号为[ -z "${var+x}" ]的解决方案,以极低的O(1)速度惩罚成本。第一作者还在代码旁边添加了这个注释,使用此解决方案给出了这个答案的URL,现在还包括为什么可以安全地省略引号的解释。

(经常)错误的方式

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

这通常是错误的,因为它不区分未设置的变量和设置为空字符串的变量。也就是说,如果var='',则上述解决方案将输出“var is blank”。

unset和“设置为空字符串”之间的区别在用户必须指定扩展名或其他属性列表并且未指定它们默认为非空值的情况下是必不可少的,而指定空字符串应该使脚本使用空的扩展名或其他属性列表。

但是,在每种情况下,区别可能并不重要。在这些情况下,[ -z "$var" ]会很好。

答案 1 :(得分:759)

要检查非空/非零字符串变量,即如果设置,请使用

if [ -n "$1" ]

-z相反。我发现自己使用的-n超过-z

您可以使用它:

if [ -n "$1" ]; then
  echo "You supplied the first parameter!"
else
  echo "First parameter not supplied."
fi

答案 2 :(得分:420)

以下是如何测试参数是未设置,还是为空(“空”)设置为值

+--------------------+----------------------+-----------------+-----------------+
|                    |       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: Parameter Expansion

  

在使用“substitute”显示的所有情况下,表达式将替换为显示的值。在使用“assign”显示的所有情况下,都会为参数分配该值,该值也会替换表达式。

答案 3 :(得分:189)

虽然这里陈述的大部分技术都是正确的,但 bash 4.2 支持对变量(man bash)的存在进行实际测试,而不是测试变量的值。

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0

值得注意的是,这种方法在用于检查set -u / set -o nounset模式中的未设置变量时不会导致错误,这与许多其他方法不同,例如使用[ -z

答案 4 :(得分:173)

有很多方法可以做到这一点,其中之一是:

if [ -z "$1" ]

如果$ 1为null或未设置

,则成功

答案 5 :(得分:61)

要查看变量是否为非空,我使用

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

如果变量未设置或为空,则相反测试:

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

要查看变量是否设置(空或非空),我使用

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

相反的测试是否未设置变量:

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments

答案 6 :(得分:55)

我总是发现other answer中的POSIX表格很慢,所以这是我对它的看法:

   +----------------------+------------+-----------------------+-----------------------+
   |   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 unset 个案,所以唯一不同的是 empty <案件得到处理。

使用前面的冒号,取消设置的情况是相同的,所以我会尽可能使用它们(即使用:=,而不仅仅是{{ 1}},因为空案例不一致。)

<强>标题

  • 设置表示=非空(VARIABLE
  • 表示VARIABLE="something"为空/ null(VARIABLE
  • 取消设置表示VARIABLE=""不存在VARIABLE

<强>值:

  • unset VARIABLE表示结果是变量的原始值。
  • $VARIABLE表示结果是提供的替换字符串。
  • "default"表示结果为null(空字符串)。
  • ""表示脚本停止执行,退出代码为127。
  • exit 127表示结果是变量的原始值,提供的替换字符串将分配给变量以供将来使用。

答案 7 :(得分:31)

在Bash的现代版本(4.2或更高版本,我认为;我不确定),我会试试这个:

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

答案 8 :(得分:19)

if [ "$1" != "" ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

虽然对于参数,我认为通常最好测试$#,即参数的数量。

if [ $# -gt 0 ]; then
  echo \$1 is set
else
  echo \$1 is not set
fi

答案 9 :(得分:15)

如果未设置

,则要退出

这对我有用。如果参数未设置,我希望我的脚本退出并显示错误消息。

#!/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}"

运行时会返回错误

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,请尝试此选项。

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

或者,即使是短暂的测试; - )

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

仅限检查,无退出 - 仅为空无效

这就是问题的答案。 如果您只想检查值set / empty = VALID或unset = INVALID。

,请使用此选项

注意,&#34; 1&#34; in&#34; ..- 1}&#34;是微不足道的, 它可以是任何东西(如x)

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

简短测试

[ "${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

答案 10 :(得分:14)

要检查变量是否设置为非空值,请使用[ -n "$x" ],正如其他人已经指出的那样。

大多数情况下,以与未设置的变量相同的方式处理具有空值的变量是个好主意。但是,如果需要,您可以区分这两者:[ -n "${x+set}" ](如果设置了"${x+set}",则set会扩展为x,如果x未设置,则会扩展为空字符串)。

要检查参数是否已通过,请测试$#,这是传递给函数的参数数量(或不在函数中时的脚本)(请参阅Paul's answer)。

答案 11 :(得分:14)

阅读bash手册页的“参数扩展”部分。参数扩展不为正在设置的变量提供常规测试,但如果未设置参数,则可以对参数执行一些操作。

例如:

function a {
    first_arg=${1-foo}
    # rest of the function
}
如果已分配,则

first_arg设置为$1,否则使用值“foo”。如果a绝对必须采用单个参数,并且不存在良好的默认值,则可以在没有给出参数时退出并显示错误消息:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(注意使用:作为空命令,它只是扩展其参数的值。在这个例子中我们不想对$1做任何事情,如果它不是,则退出不设置。

答案 12 :(得分:13)

在bash中,您可以在-v内置版

中使用[[ ]]
#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR

答案 13 :(得分:12)

对于那些希望在set -u的脚本中检查未设置或为空的人:

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

常规[ -z "$var" ]检查将失败,var; unbound variable set -u[ -z "${var-}" ] expands如果var未设置失败则会清空字符串。

答案 14 :(得分:8)

摘要

  • 使用test -n "${var-}"检查变量是否不为空(因此也必须定义/设置)。用法:

    if test -n "${name-}"; then
      echo "name is set to $name"
    else
      echo "name is not set or empty"
    fi
    
  • 使用test ! -z "${var+}"检查变量是否已定义/设置(即使它为空)。用法:

    if test ! -z "${var+}"; then
      echo "name is set to $name"
    else
      echo "name is not set"
    fi
    
    

请注意,第一个用例在shell脚本中更为常见,这就是您通常要使用的用例。

注释

  • 此解决方案应在所有POSIX shell(sh,bash,zsh,ksh,破折号)中都有效
  • 该问题的其他一些答案是正确的,但对于那些没有shell脚本经验的人来说可能会造成混淆,因此我想提供一个TLDR答案,这对于这类人来说最不会造成混淆。

说明

要了解此解决方案的工作原理,您需要了解POSIX test command和POSIX shell参数扩展(spec),因此,让我们介绍理解答案所需的绝对基础。

test命令计算一个表达式并返回true或false(通过其退出状态)。如果操作数是非空字符串,则运算符-n返回true。因此,例如,test -n "a"返回true,而test -n ""返回false。现在,要检查变量是否不为空(这意味着必须对其进行定义),可以使用test -n "$var"。但是,某些Shell脚本具有一个选项集(set -u),该选项集会导致对未定义变量的任何引用均产生错误,因此,如果未定义变量var,则表达式$a会导致一个错误。为了正确处理这种情况,您必须使用变量扩展,它会告诉Shell如果未定义变量,则用替代字符串替换该变量,从而避免上述错误。

变量扩展${var-}的意思是:如果变量var未定义(也称为“未设置”),则用空字符串替换。因此,如果test -n "${var-}"不为空,$var将返回true,这几乎总是您要在shell脚本中检查的内容。如果$var未定义或不为空,则反向检查为test -z "${var-}"

现在是第二个用例:检查是否定义了变量var,是否为空。这是一种不太常用的用例,但稍微复杂一些,我建议您阅读Lionels's great answer以便更好地理解它。

答案 15 :(得分:8)

注意

由于bash标记,我提供了以Bash为重点的答案。

简短回答

只要你只在Bash中处理命名变量,这个函数应该总是告诉你变量是否已经设置,即使它是一个空数组。

is-variable-set() {
    declare -p $1 &>dev/null
}

为什么会这样?

在Bash中(至少可以追溯到3.0),如果var是声明/设置变量,则declare -p var输出declare命令,该命令将设置变量{{1}无论当前的类型和值是什么,并返回状态代码var(成功)。如果0未声明,则var会向declare -p var输出错误消息并返回状态代码stderr。使用1,将常规&>/dev/nullstdout输出重定向到stderr,永远不会被看到,也无需更改状态代码。因此,该函数仅返回状态代码。

为什么其他方法(有时)在Bash中失败

  
      
  • /dev/null :这只会检查[ -n "$var" ]是否为非空。 (在Bash中,${var[0]}$var相同。)
  •   
  • ${var[0]}这只会检查是否设置了[ -n "${var+x}" ]
  •   
  • ${var[0]}这只会检查是否至少设置了一个[ "${#var[@]}" != 0 ]索引。
  •   

此方法在Bash中失败

这仅适用于命名变量(包括$var),而不适用于某些特殊变量($_$!$@$#,{{1 }},$$$*$?$-$0,......,以及我可能忘记的任何内容)。由于这些都不是数组,因此POSIX样式$1适用于所有这些特殊变量。但要注意将它包装在函数中,因为在调用函数时,许多特殊变量会改变值/存在。

Shell兼容性说明

如果您的脚本包含数组,并且您尝试使其与尽可能多的shell兼容,请考虑使用$2而不是[ -n "${var+x}" ]。我已经读过ksh只支持前者,但是还没有能够测试这个。我知道Bash 3.0+和Zsh 5.5.1都支持typeset -pdeclare -p,区别在于哪一个是另一个的替代。但我还没有测试过这两个关键词之外的差异,我还没有测试过其他的贝壳。

如果您需要脚本与POSIX sh兼容,那么您就无法使用数组。没有数组,typeset -p可以正常工作。

Bash

中不同方法的比较代码

此函数取消设置传递的代码变量declare -p[ -n "{$var+x}" ],运行测试以确定var代码是否设置eval,最后显示结果不同测试的状态代码。

我正在跳过varevaltest -v var,因为它们会产生与POSIX标准[ -v var ]相同的结果,同时需要Bash 4.2+。我也跳过[[ -v var ]],因为它与我测试的shell中的[ -n "${var+x}" ]相同(Bash 3.0至5.0和Zsh 5.5.1)。

typeset -p

测试用例代码

请注意,测试结果可能是意外的,因为Bash将非数字数组索引视为&#34; 0&#34;如果变量未被声明为关联数组。此外,关联数组仅在Bash 4.0 +中有效。

declare -p

测试输出

标题行中的测试助记符分别对应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\n' "$1" $nonempty $plus $count $declared } # Header. printf '%30s: %2s %2s %2s %2s\n' "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 [ -n "$var" ][ -n "${var+x}" ]

[ "${#var[@]}" != 0 ]

摘要

  
      
  • declare -p var (100%?)在Bash中测试命名变量的可靠性至少为3.0。
  •   
  • 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 在符合POSIX标准的情况下是可靠的,但无法处理数组。
  •   
  • 存在用于检查变量是否为非空的其他测试,以及用于检查其他shell中的声明变量的其他测试。但是这些测试既不适合Bash也不适用于POSIX脚本。
  •   

答案 16 :(得分:8)

为了清楚地回答 OP 如何确定变量是否设置的问题,@Lionel 的回答是正确的:

if test "${name+x}"; then
    echo 'name is set'
else
    echo 'name is not set'
fi

这个问题已经有很多答案,但没有一个提供真正布尔表达式来清楚地区分变量值。

以下是我想出的一些明确表达:

+-----------------------+-------------+---------+------------+
| Expression in script  | name='fish' | name='' | unset name |
+-----------------------+-------------+---------+------------+
| test "$name"          | TRUE        | f       | f          |
| test -n "$name"       | TRUE        | f       | f          |
| test ! -z "$name"     | TRUE        | f       | f          |
| test ! "${name-x}"    | f           | TRUE    | f          |
| test ! "${name+x}"    | f           | f       | TRUE       |
+-----------------------+-------------+---------+------------+

顺便说一下,这些表达式是等价的: test <expression> <=> [ <expression> ]

其他需要谨慎使用的歧义表达:

+----------------------+-------------+---------+------------+
| Expression in script | name='fish' | name='' | unset name |
+----------------------+-------------+---------+------------+
| test "${name+x}"     | TRUE        | TRUE    | f          |
| test "${name-x}"     | TRUE        | f       | TRUE       |
| test -z "$name"      | f           | TRUE    | TRUE       |
| test ! "$name"       | f           | TRUE    | TRUE       |
| test ! -n "$name"    | f           | TRUE    | TRUE       |
| test "$name" = ''    | f           | TRUE    | TRUE       |
+----------------------+-------------+---------+------------+

答案 17 :(得分:4)

启用Bash选项set -u时,上述答案无效。此外,它们不是动态的,例如,如何测试变量,名称“dummy”被定义?试试这个:

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

相关:In Bash, how do I test if a variable is defined in "-u" mode

答案 18 :(得分:4)

你可以这样做:

function a {
        if [ ! -z "$1" ]; then
                echo '$1 is set'
        fi
}

答案 19 :(得分:4)

使用[[ -z "$var" ]]是了解变量是否已设置的最简单方法,但该选项-z不区分未设置变量和设置为空字符串的变量:

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

最好根据变量的类型进行检查:env变量,参数或常规变量。

对于env变量:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

对于参数(例如,检查参数$5是否存在):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

对于常规变量(使用辅助功能,以优雅的方式执行):

function declare_var {
   declare -p "$1" &> /dev/null
}
declare_var "var_name" && echo "Set" || echo "Unset"

注意:

  
      
  • $#为您提供位置参数的数量。
  •   
  • declare -p为您提供作为参数传递的变量的定义。如果存在,则返回0,否则返回1并输出错误消息。
  •   
  • &> /dev/null会在不影响其返回代码的情况下抑制declare -p的输出。
  •   

答案 20 :(得分:2)

我很惊讶没有人试图编写一个 shell 脚本来以编程方式生成 the infamously hard to grok table。既然我们在这里学习编码技术,为什么不用代码表达答案呢? :) 这是我的看法(应该适用于任何 POSIX shell):

H="+-%s-+-%s----+-%s----+-%s--+\n"       # table divider printf format
R="| %-10s | %-10s | %-10s | %-10s |\n"  # table row printf format

S='V'     # S is a variable that is set-and-not-null
N=''      # N is a variable that is set-but-null (empty "")
unset U   # U is a variable that is unset

printf "$H" "----------" "-------" "-------" "---------";
printf "$R" "expression" "FOO='V'" "FOO='' " "unset FOO";
printf "$H" "----------" "-------" "-------" "---------";
printf "$R" "\${FOO:-x}" "${S:-x}" "${N:-x}" "${U:-x}  "; S='V';N='';unset U
printf "$R" "\${FOO-x} " "${S-x} " "${N-x} " "${U-x}   "; S='V';N='';unset U
printf "$R" "\${FOO:=x}" "${S:=x}" "${N:=x}" "${U:=x}  "; S='V';N='';unset U
printf "$R" "\${FOO=x} " "${S=x} " "${N=x} " "${U=x}   "; S='V';N='';unset U
printf "$R" "\${FOO:?x}" "${S:?x}" "<error>" "<error>  "; S='V';N='';unset U
printf "$R" "\${FOO?x} " "${S?x} " "${N?x} " "<error>  "; S='V';N='';unset U
printf "$R" "\${FOO:+x}" "${S:+x}" "${N:+x}" "${U:+x}  "; S='V';N='';unset U
printf "$R" "\${FOO+x} " "${S+x} " "${N+x} " "${U+x}   "; S='V';N='';unset U
printf "$H" "----------" "-------" "-------" "---------";

# For reference, the following two lines are the literal rows of the table
# which would cause the script to exit and so have had <error> written in.
#printf "$R" "\${FOO:?x}" "${S:?x}" "${N:?x}" "${U:?x}  "; S='V';N='';unset U
#printf "$R" "\${FOO?x} " "${S?x} " "${N?x} " "${U?x}   "; S='V';N='';unset U

以及运行脚本的输出:

+------------+------------+------------+------------+
| expression | FOO='V'    | FOO=''     | unset FOO  |
+------------+------------+------------+------------+
| ${FOO:-x}  | V          | x          | x          |
| ${FOO-x}   | V          |            | x          |
| ${FOO:=x}  | V          | x          | x          |
| ${FOO=x}   | V          |            | x          |
| ${FOO:?x}  | V          | <error>    | <error>    |
| ${FOO?x}   | V          |            | <error>    |
| ${FOO:+x}  | x          |            |            |
| ${FOO+x}   | x          | x          |            |
+------------+------------+------------+------------+

该脚本缺少一些功能,例如在副作用分配发生(或不发生)发生时显示,但也许其他一些更有野心的人想要从这个起点开始运行。

答案 21 :(得分:1)

我最喜欢的方式是:

$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

所以基本上,如果设置了一个变量,它就变成了对结果false&#34;的否定。 (将true =&#34;设置为&#34;)。

并且,如果它未被设置,它将变为&#34;对结果true&#34;的否定。 (因为空结果评估为true)(因此将结束为false =&#34;未设置&#34;)。

答案 22 :(得分:1)

在shell中,如果字符串的长度为零,则可以使用-z运算符,该运算符为True。

如果未设置默认MY_VAR,则设置一个简单的单行,否则您可以显示消息:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

答案 23 :(得分:1)

要测试是否设置了变量 var[ ${var+x} ]

要测试变量是否按名称设置:[ ${!name+x} ]

要测试是否设置了位置参数:[ ${N+x} ],其中 N 实际上是一个整数。

这个答案几乎与 Lionel 的相似,但通过省略 -z 探索更简约的风格。

要测试是否设置了命名变量:

function is_set {
    local v=$1
    echo -n "${v}"
    if [ ${!v+x} ]; then
        echo " = '${!v}'"
    else
        echo " is unset"
    fi
}

要测试是否设置了位置参数:

function a {
    if [ ${1+x} ]; then
        local arg=$1
        echo "a '${arg}'"
    else
        echo "a: arg is unset"
    fi
}

测试表明不需要额外注意空格和有效的测试表达式。

set -eu

V1=a
V2=
V4=-gt
V5="1 -gt 2"
V6="! -z 1"
V7='$(exit 1)'

is_set V1
is_set V2
is_set V3
is_set V4
is_set V5
is_set V6
is_set V7

a 1
a
a "1 -gt 2"
a 1 -gt 2
$./test.sh 
V1 = 'a'
V2 = ''
V3 is unset
V4 = '-gt'
V5 = '1 -gt 2'
V6 = '! -z 1'
V7 = '$(exit 1)'
a '1'
a: arg is unset
a '1 -gt 2'
a '1'

最后,注意 set -eu 可以保护我们免受常见错误的影响,例如变量名称中的拼写错误。我推荐使用它,但这意味着可以正确处理未设置变量和使用空字符串设置的变量之间的差异。

答案 24 :(得分:0)

这就是我每天都在使用的东西:

#
# 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。

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

答案 25 :(得分:0)

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

答案 26 :(得分:0)

[[ $foo ]]

或者

(( ${#foo} ))

或者

let ${#foo}

或者

declare -p foo

答案 27 :(得分:0)

我喜欢辅助功能来隐藏bash的粗略细节。在这种情况下,这样做会增加更多(隐藏)粗糙:

# 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的答案的启发),我想出了一个不同的解决方案:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p $1 &>/dev/null
}

我觉得它更直接,更腼腆,更容易理解/记忆。测试用例显示它是等效的:

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

测试用例还显示local var NOT 声明var(除非后跟&#39; =&#39;)。很长一段时间以来,我以为我用这种方式宣称变量,只是为了发现我现在只是表达了我的意图......我认为这是一个无操作。

  

IsDeclared_Tricky xyz:1
  IsDeclared_Tricky foo:1
  IsDeclared_Tricky吧:0
  IsDeclared_Tricky baz:0
  IsDeclared xyz:1
  IsDeclared foo:1
  IsDeclared bar:0
  IsDeclared baz:0

奖金:用例

我主要使用这个测试来为稍微&#34;优雅&#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

如果使用声明的所有需求变量调用:

  

Hello world!

否则:

  

错误:未声明变量:outputStr

答案 28 :(得分:0)

如果你想检查$@中的任何内容,我发现了一个(更好)更好的代码。

if [[ $1 = "" ]]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

为什么这一切? $@中的所有内容都存在于Bash中,但默认情况下它是空白的,因此test -ztest -n无法帮助您。

更新:您还可以计算参数中的字符数。

if [ ${#1} = 0 ]
then
  echo '$1 is blank'
else
  echo '$1 is filled up'
fi

答案 29 :(得分:0)

我总是使用这个,基于以下事实:任何第一次看到代码的人都很容易理解:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

并且,如果想要检查是否为空;

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

就是这样。

答案 30 :(得分:0)

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

答案 31 :(得分:0)

浏览所有答案后,这也有效:

if [[ -z $SOME_VAR ]]; then read -p "Enter a value for SOME_VAR: " SOME_VAR; fi
echo "SOME_VAR=$SOME_VAR"

如果您没有输入SOME_VAR而不是我的$SOME_VAR,它将设置为空值; $是这项工作所必需的。

答案 32 :(得分:-1)

检查变量是否已声明/未设置的函数

包括空$array=()


以下函数测试给定名称是否作为变量

存在
# 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),如果没有必要,可以避免声明的调用。
  • 如果$1包含空$array=()的名称,则声明的调用将确保我们获得正确的结果
  • 传递给/ dev / null的数据从来没有太多,因为只有在未设置变量或空数组时才会调用声明。

此功能将按以下条件进行测试:

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

  

了解更多详情

     

并且测试脚本会看到问题answer"How do I check if a variable exists in bash?"。   
  
  备注: declare -p的类似用法,因为Peregring-lk answer也显示了这种用法,这确实是巧合。否则我当然会记下它!

答案 33 :(得分:-1)

如果您希望测试变量是绑定还是未绑定,即使您打开了nounset选项,这也很有效:

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi

答案 34 :(得分:-1)

声明一个简单的函数import mpmath print(mpmath.gamma(1000)) # 4.02387260077094e+2564 ,该函数使用is_set直接测试变量是否存在。

declare -p

答案 35 :(得分:-2)

检查是否设置了var

var=""; [[ $var ]] && echo "set" || echo "not set"

答案 36 :(得分:-2)

case "$1" in
 "") echo "blank";;
 *) echo "set"
esac