在bash测试表达式中使用$@会得到奇怪的结果.
这是一个重现问题的最小测试脚本(在相同测试的替代配方中,没有错误地通过):
#! /bin/bash # file path: ./bash_weirdness.sh echo "args: '$@'" echo "--- empty ---" if test "" ; then echo "1.A1.TEST - not empty?"; fi if test -z "" ; then echo "1.A2.EMPTY - empty?"; fi if test -n "" ; then echo "1.A3.NE - not empty?"; fi if ! test "" ; then echo "1.B1.NOT.TEST - empty?"; fi if ! test -z "" ; then echo "1.B2.NOT.EMPTY - not empty?"; fi if ! test -n "" ; then echo "1.B3.NOT.NE - empty?"; fi echo "--- space ---" if test " " ; then echo "2.A1.TEST - not empty?"; fi if test -z " " ; then echo "2.A2.EMPTY - empty?"; fi if test -n " " ; then echo "2.A3.NE - not empty?"; fi if ! test " " ; then echo "2.B1.NOT.TEST - empty?"; fi if ! test -z " " ; then echo "2.B2.NOT.EMPTY - not empty?"; fi if ! test -n " " ; then echo "2.B3.NOT.NE - empty?"; fi echo "--- \$@ ---" if test "$@" ; then echo "3.A1.TEST - not empty?"; fi if test -z "$@" ; then echo "3.A2.EMPTY - empty?"; fi if test -n "$@" ; then echo "3.A3.NE - not empty?"; fi if ! test "$@" ; then echo "3.B1.NOT.TEST - empty?"; fi if ! test -z "$@" ; then echo "3.B2.NOT.EMPTY - not empty?"; fi if ! test -n "$@" ; then echo "3.B3.NOT.NE - empty?"; fi echo "--- \$* ---" if test "$*" ; then echo "4.A1.TEST - not empty?"; fi if test -z "$*" ; then echo "4.A2.EMPTY - empty?"; fi if test -n "$*" ; then echo "4.A3.NE - not empty?"; fi if ! test "$*" ; then echo "4.B1.NOT.TEST - empty?"; fi if ! test -z "$*" ; then echo "4.B2.NOT.EMPTY - not empty?"; fi if ! test -n "$*" ; then echo "4.B3.NOT.NE - empty?"; fi
前两个部分(‘空’和’空间’)在那里验证测试,测试-n和测试-z工作正常;那是多么糟糕的混乱.
当$@表示’无参数’时,即当$#为零(0)时,就会出现问题.
三次试运行表明出了什么问题:注意’3.A3.NE–不是空的?’第三轮报道:
$./bash_weirdness.sh x -> args: 'x' --- empty --- 1.A2.EMPTY - empty? 1.B1.NOT.TEST - empty? 1.B3.NOT.NE - empty? --- space --- 2.A1.TEST - not empty? 2.A3.NE - not empty? 2.B2.NOT.EMPTY - not empty? --- $@ --- 3.A1.TEST - not empty? 3.A3.NE - not empty? 3.B2.NOT.EMPTY - not empty? --- $* --- 4.A1.TEST - not empty? 4.A3.NE - not empty? 4.B2.NOT.EMPTY - not empty?
哪个好.
$./bash_weirdness.sh "" -> args: '' --- empty --- 1.A2.EMPTY - empty? 1.B1.NOT.TEST - empty? 1.B3.NOT.NE - empty? --- space --- 2.A1.TEST - not empty? 2.A3.NE - not empty? 2.B2.NOT.EMPTY - not empty? --- $@ --- 3.A2.EMPTY - empty? 3.B1.NOT.TEST - empty? 3.B3.NOT.NE - empty? --- $* --- 4.A2.EMPTY - empty? 4.B1.NOT.TEST - empty? 4.B3.NOT.NE - empty?
哪个也好.
$./bash_weirdness.sh -> args: '' --- empty --- 1.A2.EMPTY - empty? 1.B1.NOT.TEST - empty? 1.B3.NOT.NE - empty? --- space --- 2.A1.TEST - not empty? 2.A3.NE - not empty? 2.B2.NOT.EMPTY - not empty? --- $@ --- 3.A2.EMPTY - empty? 3.A3.NE - not empty? 3.B1.NOT.TEST - empty? --- $* --- 4.A2.EMPTY - empty? 4.B1.NOT.TEST - empty? 4.B3.NOT.NE - empty?
这根本不好:注意错误的’3.A3.NE’结果.
“$@”和测试不混合
test -n "$@"
此测试未正确编写. -n test需要一个参数,并告诉您该参数是否为空字符串. “$@”将扩展为一个单词,多个单词,甚至根本没有单词.因此编写测试-n“$@”是不合适的.
如果要检查参数是否已通过,请使用以下方法之一:
test $# -gt 0 [[ $# -gt 0 ]] (($# > 0)) (($#))
如果要检查参数是否已传递且非空,则使用“$*”代替. $*总是扩展为单个字符串,因此它与test -n兼容.
test -n "$*" [[ -n $* ]]
测试-n的令人困惑的情况
$test -n; echo $? 0
那么为什么这个测试通过呢?好吧,如果你没有将参数传递给-n那么bash没有看到-n作为运算符.相反,它将测试理解为一种形式
test STRING
如果你在没有运算符的情况下编写测试STRING,它隐含地等同于测试-n STRING.如果STRING非空,测试STRING是测试的简便方法.
换句话说,测试-n相当于
test -n '-n'
并且此测试通过,因为’-n’是非空字符串.
“$@”太棒了
顺便说一句,“$@”的表现实际上是一件好事. “$@”是在正确处理空格并避免单词拆分和通配的问题时访问完整参数列表的最佳方法.如有疑问,请使用“$@”.
如果要在变量中存储“$@”,请使用数组.
args=("$@") for arg in "${args[@]}"; do echo "$arg" done
这将保留“$@”的多措辞.