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

Bre*_*nt 870 scripting bash

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

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

这是正确的方法吗?(一定有更直接的东西)

duf*_*703 1177

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

if [ -z "${VAR}" ];
Run Code Online (Sandbox Code Playgroud)

  • `-z` 的倒数是 `-n` `if [ -n "$VAR" ];` (309认同)
  • `如果[!-z "$VAR" ];` (112认同)
  • 双引号确保变量不会被拆分。命令行上的简单 `$var` 将被其空格分割成一个参数列表,而 `"$var"` 将始终只有一个参数。引用变量通常是一个很好的做法,并且可以防止您被包含空格的文件名(以及其他内容)绊倒。示例:在完成 `a="x --help"` 后,尝试使用 `cat $a` - 它会给你关于 `cat` 的帮助页面。然后尝试`cat "$a"` - 它(通常)会说`cat: x --help: No such file or directory`。简而言之,尽早引用并经常引用,您几乎永远不会后悔。 (22认同)
  • 这是否包括变量是否设置为 "" 值? (14认同)
  • 是的,它确实......“-z”测试零长度字符串。 (11认同)
  • `-z` 的倒数是什么?如果不是空字符串。 (3认同)
  • 双引号`""`的意义是什么? (2认同)
  • 我觉得你的答案需要一个警告 - 也就是说,如果你的 bash 脚本有类似“set -u”的东西,那么答案将在此时中断/失败。`unset` 和 `empty` 之间有一个微妙的(通常被忽略的)区别。请注意,只有当它对您很重要或者脚本已经“set -u”时,这种区别才真正重要。 (2认同)

Den*_*son 280

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

以下任何一项:

if [[ -z $variable ]]
if [[ -z "$variable" ]]
if [[ ! $variable ]]
if [[ ! "$variable" ]]
Run Code Online (Sandbox Code Playgroud)

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

if [[ $variable ]]
Run Code Online (Sandbox Code Playgroud)

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

有关双方括号和单方括号之间差异的更多信息,请参阅我在此处的回答BashFAQ/031

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

if [[ -z ${variable+x} ]]
Run Code Online (Sandbox Code Playgroud)

其中“x”是任意的。

如果你想知道一个变量是否为空但不是未设置:

if [[ -z $variable && ${variable+x} ]]
Run Code Online (Sandbox Code Playgroud)

  • @AlastairIrvine:我在我的回答的第一句话中提到了可移植性,问题标题和正文包含“Bash”一词并且问题被标记为[tag:bash],双括号结构提供了[明显的优势](http:/ /stackoverflow.com/a/3870055/26428)在很多方面。出于一致性和可维护性的原因,我不建议混合括号样式。如果您需要最大、最小公分母的可移植性,请使用 `sh` 而不是 Bash。如果您需要它提供的增强功能,请使用 Bash 并充分利用它。 (22认同)
  • 你**可以**这样做,但是每次你把“then”放在自己的行上时,一只小狗就会死。 (6认同)
  • 我认为这比接受的答案要好。 (3认同)
  • 为什么在这样做没有任何好处的情况下推荐非便携式功能? (2认同)
  • @BrunoBronosky:我恢复了编辑。最后没有对`;` 的要求。`then` 可以放在下一行,根本没有分号。 (2认同)

Ric*_*sen 267

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

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

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

以下是如何测试各种可能性的示例,它可以在 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
Run Code Online (Sandbox Code Playgroud)

这是同样的事情,但以方便的表格形式:

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
Run Code Online (Sandbox Code Playgroud)

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

${VAR-foo}构造扩展为VARif set(包括设置为空字符串)和fooif unset 的值。这对于提供用户可覆盖的默认值很有用(例如,除非已将变量设置为某些内容,否则${COLOR-red}说使用)。redCOLOR

为什么原因[ x"${VAR}" = x ]经常被推荐用于测试变量是否为未设置或设置为空字符串是因为的一些实施方式[的命令(也称为test)是越野车。如果VAR设置为类似-n,则某些实现在给出时会做错事,[ "${VAR}" = "" ]因为 to 的第一个参数[被错误地解释为-n运算符,而不是字符串。

  • 也可以使用`[ -z "${VAR-set}" ]` 来测试设置为空字符串的变量。 (3认同)
  • 未设置检查不可靠。如果用户在 bash 中调用了 `set -u` 或 `set -o nounset`,那么测试只会导致错误“bash: VAR: unbound variable”。有关更可靠的未设置检查,请参阅 /sf/answers/970538061/。我要检查变量是否为空或未设置是`[ -z "${VAR:-}" ]`。我对变量是否非空的检查是`[ "${VAR:-}" ]`。 (2认同)

Ama*_*rus 42

-z 是最好的办法。

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

export PORT=${MY_PORT:-5432}
Run Code Online (Sandbox Code Playgroud)

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

  • 今天无意中发现了这个,正是我想要的。谢谢!我必须容忍某些脚本中的“set -o nounset”。 (2认同)

Mik*_*eyB 24

如果您有兴趣区分 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
Run Code Online (Sandbox Code Playgroud)


小智 8

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

[ "x${foo}" = "x" ]
Run Code Online (Sandbox Code Playgroud)

无论如何,如果您不允许未设置的变量(byset -uset -o nounset),那么这两种方法都会遇到麻烦。对此有一个简单的解决方法:

[ -z "${foo:-}" ]
Run Code Online (Sandbox Code Playgroud)

注意:这将使您的变量未定义。

  • http://pubs.opengroup.org/onlinepubs/009695399/utilities/test.html 上有关于`-z` 的替代方法的评论。基本上,它并不意味着要替代`-z`。相反,它处理这样的情况,其中 `$foo` 可以扩展为以元字符开头的内容,而 `[` 或 `test` 会被混淆。在开头放置任意的非元字符消除了这种可能性。 (3认同)

Luc*_*one 6

问题询问如何检查变量是否为空字符串,并且已经为此给出了最佳答案。
但是我在通过 php 编程一段时间后来到这里,我实际搜索的是一个检查,比如在 bash shell 中工作的php 中空函数
阅读答案后,我意识到我在 bash 中没有正确思考,但无论如何在那一刻,像php 中的empty这样的函数在我的 bash 代码中会非常方便。
由于我认为这可能发生在其他人身上,因此我决定

根据php 手册将 bash 中的 php 空函数转换为:
如果变量不存在或其值为以下之一,则该变量被认为是空的:

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

当然nullfalse的情况在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 "" ) ]]
}
Run Code Online (Sandbox Code Playgroud)



用法示例:

if empty "${var}"
    then
        echo "empty"
    else
        echo "not empty"
fi
Run Code Online (Sandbox Code Playgroud)



演示:
以下代码段:

#!/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
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

话虽如此,在 bash 逻辑中,此函数中的零检查可能会导致附带问题,恕我直言,任何使用此函数的人都应该评估这种风险,并可能决定切断这些检查,只留下第一个。


小智 5

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

[ "$foo" ] && echo "foo 不为空"
[ "$foo" ] || echo "foo 确实是空的"

  • 如果 foo 只包含空格,那将会失败 (4认同)
  • 如果 *foo* 以破折号开头,在某些 shell 中也会失败,因为它被解释为一个选项。例如在solaris上*ksh*、*zsh*和*bash*没有问题,*sh*和*/bin/test*会失败 (2认同)

Fed*_*TIK 5

个人更喜欢更清晰的检查方式:

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用 Bash,则应使用双方括号。对于那些可能会阅读您的答案并使用不同 shell 的人,我之前的评论是一个简单的事实陈述。 (2认同)

glu*_*k47 5

我的 5 美分:还有一个比 更短的语法if ...,这个:

VALUE="${1?"Usage: $0 value"}"
Run Code Online (Sandbox Code Playgroud)

如果提供了参数,此行将设置 VALUE,并在出现错误时打印带有脚本行号的错误消息(并终止脚本执行)。

另一个例子可以在abs-guide 中找到(搜索 «Example 10-7»)。