标题:test和bash的小坑 出处:Felix021 时间:Fri, 08 Mar 2013 12:57:12 +0000 作者:felix021 地址:https://www.felix021.com/blog/read.php?2110 内容: 昨天黄老湿问了我个问题, [ -e ] 是true还是false?为什么? ==== 啦啦啦啦啦的分割线,猜猜吧 ==== 这种坑题显然只能实践出真知:引用 $ [ -e ] && echo yes || echo no yes 果然坑了。 仔细想想,这个问题其实还是来源于实践的,比如一个很有可能会出现的写法是:引用 [ -e $somefile ] && do_sth || do_sth_else 显然,在这个情况下,如果$somefile意外地是一个空串的话,bash实际上执行的就是 [ -e ] (这个可以很容易地验证),于是返回了 true。 简单过了一下源码(coreutils/src/test.c),可以看到执行流是 value = posixtest(argc - 1 nargs); switch(nargs) case 1: //只有一个参数 return one_argument(); return argv[pos++][0] != '\0'; //检查不为空串 case 2: //只有俩参数 return two_arguments(); if (argv[pos] 是 - 开头 <且> 只有俩字符 <且> 是unary_operator) return unary_operator() switch(argv[pos][1]): case 'e': unary_advance() //里面pos加了2 return stat(argv[pos-1], &stat_buf) == 0; case .. //更多参数 test_exit(value ? TEST_TRUE : TEST_FALSE); 也就是说对于只有一个参数的情况下,test只是简单地判断这个参数是否为空(无论是不是它支持的操作符),有两个参数的情况,才会去判断是否是合法操作符,再执行相应的检测。 然后才想起来,原来我还可以看manual啊,泪流满面。。。man test,果然看到这几行:引用 -n STRING the length of STRING is nonzero STRING equivalent to -n STRING 也就是说 test STRING 等于 test -n STRING ,检查非空串,于是 [ -e ] 就等于 test -n "-e",自然就是true了。。。 对于上面提到的情况来说,解决办法是在引用变量的时候,记得加上双引号,这样test就会收到2个参数,其中第二个参数是空串,stat出错,于是就可以得到(可能原先)期望的结果了:引用 $ [ -e "$somefile" ] && echo yes || echo no no 不过话说回来,bash脚本中引用不存在的变量这件事情本来就不应该发生,类似 rm -rf $some_path/ 这样的悲剧也不是没有发生过,但是bash又没有一个 explicit 模式,所以只能自己在使用之前检测了。 通常检测一个变量是否为空,用上面的 test -n "$VAR" 或者 test -z "$VAR" 即可(注意引号),但是如果要检测某个变量是否根本不存在,BASH却没有内建方法,只能通过这种看起来很奇怪的方式(出自stack overflow): if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi //本博客3月份真高产。。。 Generated by Bo-blog 2.1.0