Mar
8
昨天黄老湿问了我个问题, [ -e ] 是true还是false?为什么?
==== 啦啦啦啦啦的分割线,猜猜吧 ====
这种坑题显然只能实践出真知:
果然坑了。
仔细想想,这个问题其实还是来源于实践的,比如一个很有可能会出现的写法是:
显然,在这个情况下,如果$somefile意外地是一个空串的话,bash实际上执行的就是 [ -e ] (这个可以很容易地验证),于是返回了 true。
简单过了一下源码(coreutils/src/test.c),可以看到执行流是
也就是说对于只有一个参数的情况下,test只是简单地判断这个参数是否为空(无论是不是它支持的操作符),有两个参数的情况,才会去判断是否是合法操作符,再执行相应的检测。
然后才想起来,原来我还可以看manual啊,泪流满面。。。man test,果然看到这几行:
也就是说 test STRING 等于 test -n STRING ,检查非空串,于是 [ -e ] 就等于 test -n "-e",自然就是true了。。。
对于上面提到的情况来说,解决办法是在引用变量的时候,记得加上双引号,这样test就会收到2个参数,其中第二个参数是空串,stat出错,于是就可以得到(可能原先)期望的结果了:
不过话说回来,bash脚本中引用不存在的变量这件事情本来就不应该发生,类似 rm -rf $some_path/ 这样的悲剧也不是没有发生过,但是bash又没有一个 explicit 模式,所以只能自己在使用之前检测了。
通常检测一个变量是否为空,用上面的 test -n "$VAR" 或者 test -z "$VAR" 即可(注意引号),但是如果要检测某个变量是否根本不存在,BASH却没有内建方法,只能通过这种看起来很奇怪的方式(出自stack overflow):
//本博客3月份真高产。。。
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。
==== 啦啦啦啦啦的分割线,猜猜吧 ====
这种坑题显然只能实践出真知:
引用
$ [ -e ] && echo yes || echo no
yes
yes
果然坑了。
仔细想想,这个问题其实还是来源于实践的,比如一个很有可能会出现的写法是:
引用
[ -e $somefile ] && do_sth || do_sth_else
显然,在这个情况下,如果$somefile意外地是一个空串的话,bash实际上执行的就是 [ -e ] (这个可以很容易地验证),于是返回了 true。
简单过了一下源码(coreutils/src/test.c),可以看到执行流是
value = posixtest(argc - 1 <as> 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);
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
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
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月份真高产。。。
欢迎扫码关注:
转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: https://www.felix021.com/blog/feed.php 。