编写脚本时,我通常使用以下语法编写 if,因为我更容易理解接下来发生的事情是不正确的。
if [ ! "$1" = "$2" ]; then
Run Code Online (Sandbox Code Playgroud)
还有人说下面的方法更好
if [ "$1" != "$2" ]; then
Run Code Online (Sandbox Code Playgroud)
问题是当我问为什么以及是否有任何差异时,似乎没有人有任何答案。
那么,这两种语法之间有什么区别吗?其中一个比另一个更安全吗?或者这只是偏好/习惯问题?
Sté*_*las 37
除了外观/偏好参数之外,一个原因可能是[ ! "$a" = "$b" ]
在极端情况下失败的实现比 with 多[ "$a" != "$b" ]
。
如果实现遵循POSIX 算法,这两种情况都应该是安全的,但即使在今天(撰写本文时 2018 年初),仍然存在失败的实现。例如,使用a='(' b=')'
:
$ (a='(' b=')'; busybox test "$a" != "$b"; echo "$?")
0
$ (a='(' b=')'; busybox test ! "$a" = "$b"; echo "$?")
1
Run Code Online (Sandbox Code Playgroud)
对于dash
0.5.9 之前的版本,例如sh
在 Ubuntu 16.04 上找到的 0.5.8 :
$ a='(' b=')' dash -c '[ "$a" != "$b" ]; echo "$?"'
0
$ a='(' b=')' dash -c '[ ! "$a" = "$b" ]; echo "$?"'
1
Run Code Online (Sandbox Code Playgroud)
(在 0.5.9 中修复,参见https://www.mail-archive.com/dash@vger.kernel.org/msg00911.html)
这些实现治疗[ ! "(" = ")" ]
的 [ ! "(" "text" ")" ]
是[ ! "text" ]
(测试是否“文本”为空字符串),而POSIX任务它是[ ! "x" = "y" ]
(测试“x”和“y”后,平等)。这些实现失败是因为它们在这种情况下执行了错误的测试。
请注意,还有另一种形式:
! [ "$a" = "$b" ]
Run Code Online (Sandbox Code Playgroud)
那个需要一个 POSIX shell(不适用于旧的 Bourne shell)。
请注意,一些实现在[ "$a" = "$b" ]
(和[ "$a" != "$b" ]
)方面也有问题,并且仍然像Solaris 10 上的[
内置程序一样/bin/sh
(Bourne shell,POSIX shell 在 中/usr/xpg4/bin/sh
)。这就是为什么您会看到以下内容:
[ "x$a" != "x$b" ]
Run Code Online (Sandbox Code Playgroud)
在试图移植到旧系统的脚本中。
该x != y
语法是更好,因为! x == y
很容易出错-需要运营商优先的知识,不同从语言到语言。语法! x == y
可以解释为!(x == y)
或(!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;
}
Run Code Online (Sandbox Code Playgroud)
返回
true
false
true
false
Run Code Online (Sandbox Code Playgroud)
在许多其他语言中可以观察到类似的行为,包括例如awk
- Unix 世界中经常使用的工具。
另一方面,将操作符聚集在一起x != y
并不会导致任何混淆,因为这是一种既定的模式。此外,从技术上讲 !=
,通常不是两个,而只是一个运算符,因此比单独比较然后否定的评估速度甚至要快一点。因此,虽然这两种语法都在 bash 中工作,但我建议遵循,x != y
因为它更容易阅读和维护遵循一些标准逻辑的代码。