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

Posted

技术标签:

【中文标题】在 Bash 中测试非零长度字符串: [ -n "$var" ] 或 [ "$var" ]【英文标题】:Test for non-zero length string in Bash: [ -n "$var" ] or [ "$var" ] 【发布时间】:2011-04-21 14:37:55 【问题描述】:

我见过 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

【问题讨论】:

【参考方案1】:

编辑:这是一个更完整的版本,显示了 [(又名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 列中,从标记为“二”的行开始,结果表明 [ 正在评估变量的 内容,就好像它们是条件表达式的一部分一样(结果匹配描述栏中的“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://***.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

【讨论】:

谢谢!我决定采用“在单括号中引用变量(第 2a 列)”IMO 的风格,-n 只会增加噪音并降低可读性。同样,对于零长度或未设置的测试,我将使用 [ ! "$var" ] 而不是 [ -z "$var" ]。 所以您的["[-n"(OP 的第一个问题)的图表显示它们是完全等价的,对吧? @hobs:是的,使用哪个取决于哪个更清楚。您还会注意到它们在使用双括号形式时的等价物,这在使用 Bash 时是首选。 所以,总结一下您的出色表格,测试非空字符串的更清晰(“更好”)的方法是 [["【参考方案2】:

就 Bash 而言,最好使用 more powerful [[

一般情况

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

以上两个结构看起来干净且可读。在大多数情况下它们应该就足够了。

请注意,我们不需要在[[ 中引用变量扩展,因为word splitting 和globbing 没有危险。

为了防止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

相关帖子和文档

有很多与此主题相关的帖子。以下是一些:

How to check if a variable is set in Bash? How to check if an environment variable exists and get its value? How to find whether or not a variable is empty in Bash What does “plus colon” (“+:”) mean in shell script expressions? Is double square brackets [[ ]] preferable over single square brackets [ ] in Bash? What is the difference between single and double square brackets in Bash? mklement0 的优秀answer[[[ Bash Hackers Wiki - [ vs [[

【讨论】:

我认为使用[[ 不一定更好。这是个人喜好的问题。即使您引用的the link 也建议始终使用[]【参考方案3】:

这里还有一些测试

如果字符串不为空则为真:

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

如果字符串为空则为真:

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

【讨论】:

这并不能回答 OP 关于什么是更好的方法的问题。【参考方案4】:

正确答案如下:

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

注意[[...]] 的使用,它会为您正确处理引用变量。

【讨论】:

为什么在 Bash 中并不真正需要 -n 时使用它? @codeforester BASH (Bourne Again Shell) 是 Bourne Shell 的后代,因此它继承了 -n-z 测试运算符,但在其顶部添加了 ! 否定。此外,这在概念上与高级语言中的==!= 之间的区别相同,高级语言提供肯定和否定运算符只是为了扩展可能的语义范围。有时组装一个不需要依赖双重否定等的表达式要容易得多。【参考方案5】:

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

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

【讨论】:

这是 Bourne shell 时代的老派。不要延续这个旧习惯。 bash 是比它的前辈更锋利的工具。 如果您避免使用 POSIX 标准明确标记为过时的语法,您甚至不需要使用 pre-bash shell。 [ "$ENV_VARIABLE" != "" ] 可以在 每个 shell 上使用符合 POSIX 的 test 实现——不仅仅是 bash,还有 ash/dash/ksh/etc。 ...也就是说,不要使用-a-o 来组合测试,而是使用[ ... ] &amp;&amp; [ ... ][ ... ] || [ ... ] 以及唯一可以适用于使用的极端情况测试中任意变量的数据是明确封闭的。【参考方案6】:

使用case/esac进行测试:

case "$var" in
  "") echo "zero length";;
esac

【讨论】:

不,请。这不是case 的用途。 case 在有两个以上备选方案时效果最佳。 case 不适合这种用途。

以上是关于在 Bash 中测试非零长度字符串: [ -n "$var" ] 或 [ "$var" ]的主要内容,如果未能解决你的问题,请参考以下文章

Bash脚本 - 查找具有非零字节内容的目录

bash if 表达式

使用 --help 参数调用的 bash 脚本应该返回 0 还是非零退出代码? [关闭]

Shell高级编程7:Shell的字符串表达式介绍

如何使用 Bash 测试文件中是不是存在字符串?

Vue.js v-for 循环遍历数组不起作用(非零长度的零元素)