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

Test for non-zero length string in Bash: [ -n “$var” ] or [ “$var” ]

我见过用两种不同的方法测试非零长度字符串的bash脚本。大多数脚本使用-n选项:

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

但是-n选项并不真正需要:

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

哪种方法更好?

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

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

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

编辑:这是一个更完整的版本,显示了[[[之间的更多区别。

下表显示了变量是否被引用、是否使用单括号或双括号以及变量是否只包含空格是影响使用带有或不带-n/-z的测试是否适合检查变量的因素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
       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列中,从标记为"2"的行开始,结果表明[正在评估变量的内容,就像它们是条件表达式的一部分一样(结果与描述列中"t"或"f"所暗示的断言相匹配)。当使用[[时(第1b列),变量内容被视为字符串,不进行计算。

第3a列和第5a列中的错误是由于变量值包含空格且变量未被引用这一事实造成的。同样,如第3b和5b列所示,[[将变量的内容作为字符串进行计算。

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

被抑制的错误消息是"预期一元运算符"或"预期二元运算符"。

这是生成上表的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/questions/3869072/test-for-non-zero-length-string-in-bash-n-var-or-var
# designed to fit an 80 character terminal

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

t () { printf"%-${w}s""true"; }
f () { [[ $? == 1 ]] && printf"%-${w}s""false" || printf"%-${w}s""-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"'

while read -r d t
do
    printf"%-${dw}s:""$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


就bash而言,最好使用更强大的[[

常见病例

1
2
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选项。

罕见病例

在我们必须区分"设置为空字符串"和"根本不设置"的罕见情况下,我们可以使用这些:

1
2
3
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测试:

1
2
3
4
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

相关职位和文件

有很多关于这个主题的文章。这里有几个:

  • 如何检查bash中是否设置了变量?
  • 如何检查环境变量是否存在并获取其值?
  • 如何在bash中查找变量是否为空
  • 在shell脚本表达式中,"+colon"("+:")是什么意思?
  • 在bash中,双方括号[]比单方括号[]更可取吗?
  • bash中的单方括号和双方括号有什么区别?
  • Mklement0给出了一个很好的答案,他谈到了[[[
  • bash黑客wiki-[vs [[


这里还有一些测试

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

1
2
3
4
5
6
7
8
[ -n"$var" ]
[[ -n $var ]]
test -n"$var"
["$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test"$var"

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

1
2
3
4
5
6
7
8
[ -z"$var" ]
[[ -z $var ]]
test -z"$var"
! ["$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test"$var"


使用case/esac进行测试

1
2
3
case"$var" in
 "") echo"zero length";;
esac


评估空env变量的另一种更透明的方法是使用…

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


正确答案如下:

1
2
3
if [[ -n $var ]] ; then
  blah
fi

注意[[...]]的用法,它正确地处理了为您引用变量的操作。