2010-09-26 64 views
11

为什么:庆典如果与或与否定

#!/bin/bash 
wtf=false 
if [ $wtf ] || [ ! -f filethatexists.whatever ] 
then 
echo "WTF1" 
fi 
if [ ! -f filethatexists.whatever ] 
then 
echo "WTF2" 
fi 

打印:

WTF1

,而不是什么?特别令人困惑的是,第二种形式按预期工作,而第一种则没有。

回答

10

基本测试

[ $wtf ] 

测试中间的字符串是否为空。

由于$wtf包含字符串'false',测试返回true,或退出状态0成功,因为'false'是不一样的空字符串'' - 因此你WTF1作为响应。

尝试:

wtf='' 

正如Gordon Davisson(和Dennis Williamson)指出,这是要小心,你正在测试的字符串是一个好主意。事实上,我应该说我总是用[ -n "$wtf" ][ -z "$wtf" ]来测试一个变量是否被设置,因为这是我在四分之一世纪以前学习shell时所必需的。我从Bash afficionados那里得到了一些反击,你不必在Bash中担心 - 但是,我认为这里的代码提供了一个反例,事实上你仍然需要担心它。

所以,一些最佳做法:

  • 用双引号括检验的变量,或
  • (在bash),使用[[ $wtf ]]它不知道如何处理的变量扩展。
  • 使用-n-z测试来测试非空值或空值。

规则可能有例外情况 - 但您不会在跟随它们时犯太多错误。

考虑代码:

wtf="1 -eq 0" 
[ $wtf ] && echo "WTF0" 
[[ $wtf ]] && echo "WTF1" 
wtf="false" 
[ $wtf ] && echo "WTF2" 
[[ $wtf ]] && echo "WTF3" 
wtf="" 
[ $wtf ] && echo "WTF4" 
[[ $wtf ]] && echo "WTF5" 
wtf="false" 
[ "$wtf" ] && echo "WTF6" 
[[ "$wtf" ]] && echo "WTF7" 
wtf="" 
[ "$wtf" ] && echo "WTF8" 
[[ "$wtf" ]] && echo "WTF9" 

产生:

WTF1 
WTF2 
WTF3 
WTF6 
WTF7 

既bash和ksh的(如在MacOS X 10.6.4发现,当与 '的bash testcode.sh' 或运行'ksh testcode.sh')。一个真正的Bourne shell(如果你仍然可以找到这样的东西)会反对双括号操作 - 它将无法在$PATH上找到命令'[['。

您可以扩展测试以涵盖更多令人厌恶的病例。

+0

好的,有道理。语法高亮让我意识到布尔是给定的。猜猜我预料太多了。 – i30817 2010-09-26 23:04:17

+0

实际上,它甚至比这更伟大 - 如果$ wtf中有任何空格,它将被评估为一个表达式。尝试使用'wtf =“1 -eq 0”'和'wtf =“1 -eq 1'来查看效果。对于更多喜剧,请尝试'wtf =”1 -eq“' – 2010-09-27 02:41:56

+0

测试4/5是测试8/9的副本我认为你的意思是在变量周围没有引号的情况下做4/5(但结果是一样的 - 没有任何回应),另外,通过引用变量改变测试0/1不会评估'1 -eq 0',因此两个括号类型的计算结果都为true(如测试2/3)。有趣的是,在Bash和ksh中,每个[[']],[[']]和[]都是工作,并返回false,但'[[]]'产生一个错误, – 2010-09-27 03:25:31

0

if [ $wtf = true ] || [ ! -f . .

+0

甚至“if [[$ wtf == true]] || [! -f ...“ – dimba 2010-09-26 23:37:04

3

这里的一个方便的小窍门:

wtf=false 
if $wtf || [ ! -f filethatexists.whatever ] 

在这种形式中,变量的内容被执行并返回值确定测试是否通过或失败。碰巧truefalse是返回适当值的Bash内建函数。

+1

这个”方便的小技巧“并不是很好的做法,如果你有一个代码路径,其中'wtf'包含'true'或'false'以外的任何东西, $?'继续!'rm -rf /'?Err ... – 2015-07-17 22:54:15