题 如何确定bash变量是否为空?


确定bash中的变量是否为空(“”)的最佳方法是什么?

我听说我建议这样做 if [ "x$variable" = "x" ]

是那个 正确 办法? (必须有一些更直接的东西)


719
2018-05-12 17:54






答案:


如果未设置变量或将变量设置为空字符串(“”),则返回true。

if [ -z "$VAR" ];

980
2018-05-12 18:06



这是否包括变量IS SET为值“”? - Brent
是的它......“ - z”测试零长度字符串。 - David Z
if [ ! -z "$VAR" ]; - Aaron Copley
逆的 -z 是 -n  if [ -n "$VAR" ]; - Felipe Alvarez
双引号确保变量不会被拆分。一个简单的 $var 命令行上的空格将被空格拆分为参数列表 "$var" 永远只会是一个参数。引用变量通常是一种很好的做法,可以阻止你绊倒包含空格的文件名(以及其他内容)。例子:做完之后 a="x --help",试试 cat $a  - 它会为您提供帮助页面 cat。然后试试 cat "$a"  - 它(通常)会说 cat: x --help: No such file or directory。简而言之,提前引用并经常引用,你几乎不会后悔。 - Score_Under


在Bash中,当您不关心不支持它的shell的可移植性时,您应该始终使用双括号语法:

以下任何一项:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]

在Bash中,使用双方括号,引号不是必需的。您可以简化对变量的测试  包含一个值:

if [[ $variable ]]

此语法与ksh兼容(至少ksh93,无论如何)。它不适用于纯POSIX或较旧的Bourne shell,例如sh或dash。

看到 我的答案在这里 和 BashFAQ / 031 有关双方括号和单方括号之间差异的更多信息。

您可以测试以查看变量是否被特别取消设置(与空字符串不同):

if [[ -z ${variable+x} ]]

其中“x”是任意的。

如果您想知道变量是否为null但未设置:

if [[ -z $variable && ${variable+x} ]]

227
2018-02-25 03:37



那 if [[ $variable ]] 为我工作得很好,甚至不需要 set -u 这是其他一个提出的解决方案所要求的。 - Teemu Leisti
我认为这比接受的答案要好。 - qed
为什么在推荐非便携功能时这样做没有任何好处? - Alastair Irvine
@AlastairIrvine:我在答案的第一句中提到可移植性,问题标题和正文包含“Bash”这个词,问题被标记 庆典,和双支架结构提供 明显的优势 在许多方面。出于一致性和可维护性的原因,我不建议混合支架样式。如果您需要最大,最小公分母可移植性,请使用 sh 而不是Bash。如果您需要增加的功能,请使用Bash并完全使用它。 - Dennis Williamson
@BrunoBronosky:我还原了编辑。没有要求 ; 在末尾。该 then 可以在下一行没有分号。 - Dennis Williamson


bash中的变量(以及任何与POSIX兼容的shell)可以处于以下三种状态之一:

  • 未设置
  • 设置为空字符串
  • 设置为非空字符串

大多数情况下,您只需要知道变量是否设置为非空字符串,但有时区分unset和设置为空字符串很重要。

以下是如何测试各种可能性的示例,它适用于bash或任何POSIX兼容的shell:

if [ -z "${VAR}" ]; then
    echo "VAR is unset or set to the empty string"
fi
if [ -z "${VAR+set}" ]; then
    echo "VAR is unset"
fi
if [ -z "${VAR-unset}" ]; then
    echo "VAR is set to the empty string"
fi
if [ -n "${VAR}" ]; then
    echo "VAR is set to a non-empty string"
fi
if [ -n "${VAR+set}" ]; then
    echo "VAR is set, possibly to the empty string"
fi
if [ -n "${VAR-unset}" ]; then
    echo "VAR is either unset or set to a non-empty string"
fi

这是相同的东西,但在方便的表格形式:

                        +-------+-------+-----------+
                VAR is: | unset | empty | non-empty |
+-----------------------+-------+-------+-----------+
| [ -z "${VAR}" ]       | true  | true  | false     |
| [ -z "${VAR+set}" ]   | true  | false | false     |
| [ -z "${VAR-unset}" ] | false | true  | false     |
| [ -n "${VAR}" ]       | false | false | true      |
| [ -n "${VAR+set}" ]   | false | true  | true      |
| [ -n "${VAR-unset}" ] | true  | false | true      |
+-----------------------+-------+-------+-----------+

${VAR+foo} 如果构造扩展为空字符串 VAR 未设置或未完成 foo 如果 VAR 设置为任何内容(包括空字符串)。

${VAR-foo} 构造扩展到的值 VAR 如果设置(包括设置为空字符串)和 foo 如果没有设定。这对于提供用户可覆盖的默认值很有用(例如, ${COLOR-red} 说要用 red 除非变量 COLOR 已被设置为某事)。

之所以 [ x"${VAR}" = x ] 通常建议用于测试变量是否未设置或设置为空字符串是因为某些实现的 [ 命令(也称为 test)是马车。如果 VAR 设置为类似的东西 -n,然后一些实现将在给出时做错事 [ "${VAR}" = "" ] 因为第一个参数 [ 被错误地解释为 -n 运算符,而不是字符串。


205
2018-04-24 20:39



测试设置为空字符串的变量也可以使用 [ -z "${VAR-set}" ]。 - nwellnhof
@nwellnhof:谢谢!我更新了我的答案以使用简短的语法。 - Richard Hansen
@FaheemMitha:这不是你的错 - 我的回答很难读。我添加了一张表,希望能让答案更加清晰。 - Richard Hansen
@RichardHansen:谢谢,这是一个有用的补充。 - Faheem Mitha
未设置的检查不可靠。如果用户打电话 set -u 要么 set -o nounset 在bash中,那么测试只会导致错误“bash:VAR:unbound variable”。看到 stackoverflow.com/a/13864829 为了更可靠的未设置检查。我的检查变量是null还是未设置是 [ -z "${VAR:-}" ]。我检查变量是否为非空是 [ "${VAR:-}" ]。 - Kevin Jin


-z 是一种最好的方式。

我使用的另一个选项是设置变量,但它可以被另一个变量覆盖,例如

export PORT=${MY_PORT:-5432}

如果 $MY_PORT 变量是空的,然后 PORT 设置为5432,否则PORT设置为值 MY_PORT。请注意语法包括冒号和破折号。


36
2018-06-11 13:19



今天意外地发现了这一点,这正是我想要的。谢谢!我不得不忍受 set -o nounset 在一些脚本中。 - opello


如果您有兴趣区分set-empty和unset状态的情况,请查看bash的-u选项:

$ set -u
$ echo $BAR
bash: BAR: unbound variable
$ [ -z "$BAR" ] && echo true
bash: BAR: unbound variable
$ BAR=""
$ echo $BAR

$ [ -z "$BAR" ] && echo true
true

24
2018-05-12 18:21





我见过的替代品 [ -z "$foo" ] 是以下,但我不确定为什么人们使用这种方法,任何人都知道?

[ "x${foo}" = "x" ]

无论如何,如果你不允许未设置的变量(通过 set -u 要么 set -o nounset),那么你将遇到这两种方法的麻烦。有一个简单的解决方法:

[ -z "${foo:-}" ]

注意:这将保留您的变量undef。


8
2017-10-20 03:58



有关于替代品的评论 -z 在 pubs.opengroup.org/onlinepubs/009695399/utilities/test.html。基本上,它不是一个替代品 -z。相反,它处理的情况 $foo 可以扩展到以元字符开头的东西 [ 要么 test 会被混淆。在开头放置任意非元字符消除了这种可能性。 - James Sneeringer


 问 如何检查变量是否为空字符串 并且已经给出了最好的答案。
但是我经过一段时间在PHP中编程后才登陆这里,我实际上搜索的是一张像是一样的支票 php中的空函数 在bash shell中工作。
看完答案之后,我意识到我在bash中没有正确思考,但无论如何在那一刻就像是一个功能  在我的bash代码中,在php中会非常方便。
我认为这可能发生在其他人身上,我决定在bash中转换php空函数

根据 php手册
如果变量不存在或者其值为以下值之一,则该变量被视为空:

  • “”(空字符串)
  • 0(0为整数)
  • 0.0(0作为浮点数)
  • “0”(0作为字符串)
  • 一个空数组
  • 声明的变量,但没有值

当然了 空值 和  case无法在bash中转换,因此省略它们。

function empty
{
    local var="$1"

    # Return true if:
    # 1.    var is a null string ("" as empty string)
    # 2.    a non set variable is passed
    # 3.    a declared variable or array but without a value is passed
    # 4.    an empty array is passed
    if test -z "$var"
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is zero (0 as an integer or "0" as a string)
    elif [ "$var" == 0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return

    # Return true if var is 0.0 (0 as a float)
    elif [ "$var" == 0.0 2> /dev/null ]
    then
        [[ $( echo "1" ) ]]
        return
    fi

    [[ $( echo "" ) ]]
}



用法示例:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi



演示:
以下代码段:

#!/bin/bash

vars=(
    ""
    0
    0.0
    "0"
    1
    "string"
    " "
)

for (( i=0; i<${#vars[@]}; i++ ))
do
    var="${vars[$i]}"

    if empty "${var}"
        then
            what="empty"
        else
            what="not empty"
    fi
    echo "VAR \"$var\" is $what"
done

exit

输出:

VAR "" is empty
VAR "0" is empty
VAR "0.0" is empty
VAR "0" is empty
VAR "1" is not empty
VAR "string" is not empty
VAR " " is not empty

虽然在bash逻辑中说这个函数中的零检查可能会导致副问题,任何使用此函数的人都应该评估这个风险,并且可能决定将这些检查切掉而只留下第一个。


6
2017-08-31 20:11



功能内部 empty  - 你为什么写 [[ $( echo "1" ) ]] ; return 而不是简单 return 1 ? - Dor


整个if-then和-z是不必要的。

[“$ foo”] && echo“foo不为空”
[“$ foo”] ||回声“foo确实是空的”

5
2018-01-26 14:02



如果foo只包含空格,那将失败 - Brian
如果是,也会失败 FOO 以破折号开头,因为它被解释为一个选项。例如。在solaris上 KSH, zsh的 和 庆典 没问题, SH 和 /斌/测试 将失败 - ktf