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

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

function a {
    # if $1 is set ?
}

当前回答

我很惊讶没有人尝试编写一个shell脚本来以编程方式生成这个臭名昭著的难以摸索的表。既然我们在这里试图学习编码技术,为什么不用代码表达答案?:)这是我的看法(应该在任何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
#                                  "${N:?x}" "${U:?x}  "
printf "$R" "\${FOO:?x}" "${S:?x}" "<error>" "<error>  "; S='V';N='';unset U
#                                            "${U?x}   "
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" "----------" "-------" "-------" "---------";

以及运行脚本的输出:

+------------+------------+------------+------------+
| 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          |            |
+------------+------------+------------+------------+

该脚本缺少了一些功能,比如在发生(或不发生)副作用分配时显示,但也许其他更有野心的人希望以此为出发点,并以此为出发。

其他回答

我很惊讶没有人尝试编写一个shell脚本来以编程方式生成这个臭名昭著的难以摸索的表。既然我们在这里试图学习编码技术,为什么不用代码表达答案?:)这是我的看法(应该在任何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
#                                  "${N:?x}" "${U:?x}  "
printf "$R" "\${FOO:?x}" "${S:?x}" "<error>" "<error>  "; S='V';N='';unset U
#                                            "${U?x}   "
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" "----------" "-------" "-------" "---------";

以及运行脚本的输出:

+------------+------------+------------+------------+
| 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          |            |
+------------+------------+------------+------------+

该脚本缺少了一些功能,比如在发生(或不发生)副作用分配时显示,但也许其他更有野心的人希望以此为出发点,并以此为出发。

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

if [ -z "$1" ]

如果$1为空或未设置,则此操作成功。

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

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

常规[-z“$var”]检查将因var而失败;未绑定变量如果设置-u但[-z“${var-}”]如果var未设置而不失败,则扩展为空字符串。

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

当启用Bash选项集-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.
}

相关:在Bash中,如何测试变量是否以“-u”模式定义