Bash 用或和否定来击打

Bash 用或和否定来击打,bash,Bash,为什么: #!/bin/bash wtf=false if [ $wtf ] || [ ! -f filethatexists.whatever ] then echo "WTF1" fi if [ ! -f filethatexists.whatever ] then echo "WTF2" fi 打印: WTF1 而不是什么都没有?尤其令人困惑的是,第二种形式的效果与预期的一样,而第一种形式的效果却不一样。基本测试 [ $wtf ] 测试中间字符串是否为空。 由于$wtf包含字符串'

为什么:

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

WTF1

而不是什么都没有?尤其令人困惑的是,第二种形式的效果与预期的一样,而第一种形式的效果却不一样。

基本测试

[ $wtf ]

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

由于
$wtf
包含字符串
'false'
,测试将返回true,或退出状态0以获得成功,因为
'false'
与空字符串
'
不同,因此您将得到
WTF1
作为响应

尝试:

wtf=''

正如(和)所指出的,小心测试的字符串是一个好主意。事实上,我应该声明,我将始终使用
[-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
上找到命令“
[


您可以扩展测试以覆盖更多令人厌恶的情况。

如果[$wtf=true]| |[!-f..
这里有一个简便的小技巧:

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

在这种形式中,变量的内容被执行,返回值决定测试是通过还是失败。碰巧
true
false
是Bash内置的,返回适当的值。

ok,有意义。语法突出显示让我觉得布尔值是给定的。我猜我期望太多了。Ac实际上,它甚至比这更奇怪——如果$wtf中有空格,它将作为一个表达式进行计算。使用
wtf=“1-eq 0”
wtf=“1-eq 1”
进行尝试,以查看效果。要想获得更多的喜剧效果,请尝试
wtf=“1-eq”
Test 4/5是Test 8/9的副本。我认为您打算在变量周围不加引号的情况下进行4/5(但结果是一样的-没有任何结果)。此外,通过引用变量改变的测试0/1不会计算
1-eq 0
,因此两种括号类型的计算结果都为true(如测试2/3)。有趣的是,在Bash和ksh中,
[']
[']
[]
每一项都有效,但返回false
[[]]
产生错误。甚至“如果[$wtf==true]| |[!-f…”@dimba这是一种bash主义,但是,&您不能在bash或bash兼容的shell之外运行它。这是一个“方便的小把戏”“这几乎不是好的做法。如果您有一个代码路径,其中
wtf
包含除
true
false
以外的任何内容,则会产生令人惊讶的行为结果。空字符串?先前的
$?
值继续存在!
rm-rf/
?错误。。。