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


Answers:


1053

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

if [ -z "$VAR" ];

14
这是否包括变量是否设置为“”值?
布伦特

11
是的,它确实...“ -z”测试零长度的字符串。
David Z

91
if [ ! -z "$VAR" ];
亚伦·科普利

263
相反的-z-n if [ -n "$VAR" ];
Felipe Alvarez

19
双引号确保变量不会拆分。$var命令行中的简单命令将由其空格分隔为参数列表,而"$var"始终仅是一个参数。经常给变量加引号是一种好习惯,它可以阻止您跳入包含空格的文件名(等等)。示例:完成后a="x --help",请尝试cat $a-将为您提供帮助页面cat。然后尝试cat "$a"-(通常)会说cat: x --help: No such file or directory。简而言之,尽早报价并经常报价,您几乎永远不会后悔。
2014年

247

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

以下任何一项:

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

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

if [[ $variable ]]

该语法与ksh兼容(无论如何至少与ksh93兼容)。在纯POSIX或更旧的Bourne外壳(例如sh或破折号)中不起作用。

请参阅我的答案BashFAQ / 031,以获取有关双方括号和单方括号之间区别的更多信息。

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

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

其中“ x”是任意的。

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

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

1
if [[ $variable ]]对我来说很好,甚至不需要set -u其他提议的解决方案之一。
Teemu Leisti 2012年

3
我认为这比公认的答案更好。
q

2
为什么在推荐无用功能时却没有好处呢?
Alastair Irvine

19
@AlastairIrvine:我在回答的第一句话中提到了可移植性,问题标题和正文中包含“ Bash”一词,问题被标记为bash,双括号结构在许多方面都具有明显的优势。而且出于一致性和可维护性的原因,我不建议混合使用括号样式。如果您需要最大,最低的公分母可移植性,请使用sh代替Bash。如果您需要它提供的增强功能,请使用Bash并充分使用它。
丹尼斯·威廉姆森

2
@BrunoBronosky:我还原了编辑。;最后没有要求。该then可在下一行没有分号的。
丹尼斯·威廉姆森

230

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

这是同一件事,但以方便的表格形式出现:

                        +-------+-------+-----------+
                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}if结构扩展为空字符串VAR未设置或foo如果VAR设置为任何东西(包括空字符串)。

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

[ x"${VAR}" = x ]经常建议之所以测试变量是未设置还是设置为空字符串,是因为该[命令的某些实现(也称为test)存在错误。如果VAR将设置为-n,则某些实现在执行时会做错事情,[ "${VAR}" = "" ]因为to的第一个参数[被错误地解释为-n运算符,而不是字符串。


3
也可以使用来测试设置为空字符串的变量[ -z "${VAR-set}" ]
nwellnhof

@nwellnhof:谢谢!我更新了答案,以使用更简短的语法。
理查德·汉森

第一个和最后一个构造有什么区别?它们都对应于“ VAR未设置或设置为非空字符串”。
Faheem Mitha

1
@FaheemMitha:这不是你的错-我的答案很难看。我添加了一个表格,希望可以使答案更加清楚。
理查德·汉森

2
未设置的检查不可靠。如果用户使用bash 调用set -uset -o nounset,则测试只会导致错误“ bash:VAR:未绑定变量”。有关更可靠的未设置检查,请参见stackoverflow.com/a/13864829。我检查变量是否为null或未设置为[ -z "${VAR:-}" ]。我检查变量是否为非空为[ "${VAR:-}" ]
凯文·金

38

-z 是最好的方法。

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

export PORT=${MY_PORT:-5432}

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


今天偶然发现了这个,这正是我想要的。谢谢!我必须容忍set -o nounset某些脚本。
opello 2012年

24

如果您想区分设置为空和未设置状态,请查看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

8

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

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

无论如何,如果您不允许使用unset变量(通过set -uset -o nounset),那么这两种方法都会遇到麻烦。有一个简单的解决方法:

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

注意:这将使您的变量为undef。


3
-zpubs.opengroup.org/onlinepubs/009695399/utilities/test.html上有关于替代方法的评论。基本上,它并不是的替代-z。相反,它处理的情况$foo可能会扩展到以元字符开头[test会被其混淆的内容。在开始时放置一个任意的非元字符可以消除这种可能性。
James Sneeringer

6

问题询问如何检查变量是否为空字符串,并且已经给出最佳答案。
但是经过一段时期的php编程之后,我来到了这里,而我真正要搜索的是一个检查,例如在bash shell中工作的php中空函数
阅读答案后,我意识到我在bash中的想法不正确,但是在那一刻,在bash代码中,像php中的empty这样的函数还是很方便的。
因为我认为这可能发生在其他人身上,所以我决定

根据bash 手册将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 "" ) ]]
}



用法示例:

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逻辑中,此功能对零的检查会引起恕我直言的副作用,使用此功能的任何人都应该评估这种风险,并可能决定取消那些检查,只保留第一个检查。


在函数内部empty-为什么要编写[[ $( echo "1" ) ]] ; return而不是简单编写return 1
Dor

5

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

[“ $ foo”] &&回显“ foo不为空”
[“ $ foo”] || 回显“ foo确实为空”

3
如果foo仅包含空格,则该操作将失败
Brian

2
如果foo以破折号开头,则在某些shell中也会失败,因为foo被解释为选项。例如,在solaris kshzshbash上都没问题,sh/ bin / test将失败
ktf

4

确实在$ FOO设置为空时正确:

[ "${FOO+x}" = x ] && [ -z "$FOO" ]

4

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

if [ "${VARIABLE}" == "" ]; then
  echo VARIABLE is empty
else
  echo VARIABLE is not empty
fi

1
一些外壳不接受双等号。
丹尼斯·威廉姆森

1
问题是关于bash。我正在使用bash。对我来说效果很好。您到底在说什么?
Fedir RYKHTIK '02

2
如果您使用的是Bash,则应使用双方括号。对于那些可能阅读您的答案并使用其他Shell的人,我之前的评论是一个简单的事实陈述。
丹尼斯·威廉姆森

单方括号在这种情况下确定,请参阅serverfault.com/questions/52034/...
卢卡Borrione


4

我的5美分:还有比if ...这短的语法:

VALUE="${1?"Usage: $0 value"}"

如果提供了参数,则该行将设置VALUE,并在出现错误的情况下显示一条以脚本行号开头的错误消息(并终止脚本执行)。

可以在abs指南中找到另一个示例(搜索“示例10-7”)。


0

没有确切的答案,但是遇到了这个窍门。如果您要查找的字符串来自“命令”,那么您实际上可以将命令存储在环境中。变量,然后每次对if语句执行一次,则不需要括号!

例如,此命令确定您是否使用debian:

grep debian /proc/version

完整的例子:

IS_DEBIAN="grep -i debian /proc/version"

if $IS_DEBIAN; then
  echo 'yes debian'
else
  echo 'non debian'
fi

因此,这就像一种间接方法(每次都运行它)来检查一个空字符串(它恰好是在检查命令的错误响应,但它恰好正在返回一个空字符串)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.