在编写脚本时,我通常使用以下语法编写 if,因为这样我更容易理解接下来发生的事情是不正确的。
if [ ! "$1" = "$2" ]; then
还有人说下面的方式比较好
if [ "$1" != "$2" ]; then
问题是,当我问为什么以及是否存在任何差异时,似乎没有人给出任何答案。
那么,这两种语法有什么区别吗?其中一个比另一个更安全吗?或者这只是一个偏好/习惯的问题?
答案1
除了装饰/偏好参数之外,原因之一可能是[ ! "$a" = "$b" ]
在极端情况下失败的实现比[ "$a" != "$b" ]
.
如果实施遵循,这两种情况都应该是安全的POSIX 算法,但即使在今天(截至撰写本文时为 2018 年初),仍然存在失败的实现。例如,与a='(' b=')'
:
$ (a='(' b=')'; busybox test "$a" != "$b"; echo "$?")
0
$ (a='(' b=')'; busybox test ! "$a" = "$b"; echo "$?")
1
对于0.5.9 之前的版本,例如 Ubuntu 16.04 上的dash
0.5.8 :sh
$ a='(' b=')' dash -c '[ "$a" != "$b" ]; echo "$?"'
0
$ a='(' b=')' dash -c '[ ! "$a" = "$b" ]; echo "$?"'
1
(0.5.9 中已修复,请参阅https://www.mail-archive.com/[电子邮件受保护]/msg00911.html)
这些实现就这样对待[ ! "(" = ")" ]
( [ ! "(" "text" ")" ]
测试[ ! "text" ]
“text”是否为空字符串),而 POSIX 强制要求如此[ ! "x" = "y" ]
(测试“x”和“y”是否相等)。这些实现失败是因为它们在这种情况下执行了错误的测试。
请注意,还有另一种形式:
! [ "$a" = "$b" ]
那个需要一个 POSIX shell(不能与旧的 Bourne shell 一起使用)。
注意一些实现也遇到了[ "$a" = "$b" ]
( 和) 的问题[ "$a" != "$b" ]
并且仍然像Solaris 10 上[
的内置一样/bin/sh
(Bourne shell,POSIX shell 位于 中/usr/xpg4/bin/sh
)。这就是为什么你会看到这样的东西:
[ "x$a" != "x$b" ]
在试图移植到旧系统的脚本中。
答案2
语法x != y
更好,因为! x == y
容易出错 - 需要了解不同语言的运算符优先级。语法! x == y
可以解释为!(x == y)
or (!x) == y
,具体取决于!
vs的优先级=
。
例如,在c++
否定中!
出现在比较/关系运算符之前 ==
,因此有以下代码:
#include<iostream>
using namespace std;
int main()
{
int x=1, y=2;
if( x != y ) cout<<"true"<<endl; else cout<<"false"<<endl;
if( ! x == y ) cout<<"true"<<endl; else cout<<"false"<<endl;
if( !( x == y ) ) cout<<"true"<<endl; else cout<<"false"<<endl;
if( (!x) == y ) cout<<"true"<<endl; else cout<<"false"<<endl;
}
回报
true
false
true
false
在许多其他语言中也可以观察到类似的行为,包括awk
Unix 世界中常用的工具。
另一方面,x != y
作为一种行之有效的模式,将运营商聚集在一起不会导致任何混乱。此外,从技术上讲, !=
通常不是两个,而是一个运算符,因此评估速度应该比单独比较然后求反要快一些。因此,虽然这两种语法都可以在 bash 中使用,但我建议遵循,x != y
因为遵循某些标准逻辑的代码更容易阅读和维护。
答案3
这种事情是非常基于观点,因为“答案”很大程度上取决于个人大脑的连接方式。虽然在语义上确实NOT ( A == B )
与 相同(A != B )
,但一个人可能更清楚,而另一个人可能更清楚。它也依赖于上下文。例如,如果我设置了一个标志,则使用一种语法比另一种语法的含义可能更清晰:
if NOT ( fileHandleStatus == FS_OPEN )
相对于
if ( fileHandleStatus != FS_OPEN )