在Bash中测试非零长度字符串:[-n“ $ var”]或[“ $ var”]


181

我已经看到Bash脚本以两种不同的方式测试非零长度的字符串。大多数脚本使用以下-n选项:

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

但是实际上不需要-n选项:

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

哪个更好?

同样,这是测试零长度的更好方法:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

要么

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi

Answers:


393

编辑:这是一个更完整的版本,显示[(aka test)和之间的更多差异[[

下表显示了变量是否被引用,是否使用单括号或双括号以及该变量是否仅包含空格,这些都会影响使用带有或不带有测试的测试-n/-z是否适合检查变量。

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

如果您想知道变量的长度是否为非零,请执行以下任一操作:

  • 用单括号括住变量(第2a栏)
  • -n在单括号中使用并引用该变量(第4a栏)
  • 使用双括号,带或不带引号,带或不带引号-n(列1b-4b)

注意,在第1a列中从标记为“ two”的行开始,结果表明[正在评估变量的内容,就好像它们是条件表达式的一部分一样(结果与变量T中的“ T”或“ F”所隐含的断言相匹配)。说明列)。当[[使用时(第1b列),变量内容被视为字符串且未评估。

列3a和5a中的错误是由以下事实引起的:变量值包含空格,并且变量未引用。再次,如列3b和5b所示,[[将变量的内容评估为字符串。

相应地,对于零长度字符串的测试,列6a,5b和6b显示了正确的方法。还要注意,如果求反的意图比使用相反的操作更清楚,则可以否决所有这些测试。例如:if ! [[ -n $var ]]

如果您使用[,请确保引用变量是确保您不会得到意外结果的关键。使用[[,没关系。

被抑制的错误消息是“期望一元运算符”或“期望二元运算符”。

这是产生上表的脚本。

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF

1
谢谢!我决定采用IMO的“在单括号中引用变量(第2a栏)”的样式,-n只会增加噪音并降低可读性。同样,为了测试零长度或未设置长度,我将使用[!“ $ var”]而不是[-z“ $ var”]。
AllenHalsey 2010年

2
因此,您对["vs 的图表[-n"(OP的第一个问题)表明它们完全等效,对吧?
滚刀

1
@hobs:是的,使用哪个取决于哪个更清楚。您还会注意到,使用双括号形式时,它们的等效项是使用Bash时的首选。
暂停,直到另行通知。

1
因此,总结一下您的真棒表,测试非空字符串的更清晰(更好)的方法是[["
滚刀

22

就Bash而言,最好使用更强大的功能 [[

通常情况

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

上面的两个构造看起来很干净而且可读。在大多数情况下,它们就足够了。

请注意,我们不需要引用内部的变量扩展名,[[因为没有分和乱序的危险。

为了防止shellcheck[[ $var ]]和的软抱怨[[ ! $var ]],我们可以使用该-n选项。

稀有案例

在极少数情况下,我们必须在“设置为空字符串”与“根本不设置”之间进行区分,可以使用以下命令:

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

我们还可以使用-v测试:

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

相关帖子和文档

有很多与此主题相关的帖子。这里有一些:


9

这是更多测试

如果字符串不为空,则为true:

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

如果字符串为空,则为true:

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"

这不能回答OP关于什么是更好方法的问题。
codeforester

0

正确答案如下:

if [[ -n $var ]] ; then
  blah
fi

请注意,使用[[...]]可以正确地为您引用变量。


2
为什么-n在Bash真正不需要时使用?
codeforester

0

评估空环境变量的另一种可能是更透明的方法是使用...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi

10
从伯恩壳牌时代开始,这是非常古老的派。不要永久保留这个旧习惯。bash比其前任产品更强大。
tbc0

1
如果要避免使用POSIX标准显式标记为过时的语法,则甚至不需要在bash之前的外壳中使用它。[ "$ENV_VARIABLE" != "" ]可以在所有与POSIX兼容的外壳上使用test实现的 -不仅是bash,而且是ash / dash / ksh / etc。
查尔斯·达菲

...也就是说,不使用-a-o组合测试,而是使用[ ... ] && [ ... ]或,[ ... ] || [ ... ]并且明确适用于在测试中使用任意变量的数据的唯一极端情况。
查尔斯·达菲

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.