Bash:删除括号内所有出现的 -n 是否安全?

Bash: Safe to remove all occurrences of -n inside brackets?

我最近在我的 bash 脚本中发现了这个 "bug";

if [ "$var" ]; then
    echo "Condition is true"
fi

我的意思是检查 $var 是否非空,即 [ -n "$var" ]。碰巧的是,没有 -n,代码似乎工作得很好。同样,我发现我可以用 [ ! "$var" ].

替换 [ -z "$var" ]

我倾向于喜欢这种基于其他语言中变量的(非)空性的隐式虚假性(真实性),因此我可能也会在 bash 中采用这种模式。这样做有什么危险吗,即两组语法不等价的边缘情况?

所以我们代入:

-n "$var"   ->    "$var" 
-z "$var"   ->    ! "$var"

这看起来不错,有些人也这样做了。在极端情况下,删除会有害并导致语法错误。这些极端情况特别包括时间,其中 var 等于有效的 test 参数。前任。 var=-nvar="!"

例如:

$ v1="-n" v2=""; [ -n "$v1" -o -z "$v2" ]; echo $?
0

但是

$ v1="-n" v2=""; [ "$v1" -o ! "$v2" ]; echo $?
bash: [: too many arguments
2

也就是说,我无法在我的系统 (bash 5.0.0) 上找到不使用 -o-a 来破解它的方法。无论如何,测试手册页建议使用 &&|| 而不是 -a-o.

但是在POSIX specification test中我们可以找到如下应用笔记:

The two commands:

test ""
test ! ""

could not be used reliably on some historical systems. Unexpected results would occur if such a string expression were used and expanded to '!', '(', or a known unary primary. Better constructs are:

test -n ""
test -z ""

所以我认为只要你不使用"some historical systems",你就是安全的。但值得冒险吗?你必须自己回答。

也就是说,主观的:我更看重可维护性和可读性,然后节省输入 3 个字符并发现 -n-z 更具可读性。 -n 的意图很明确 - 测试字符串的长度是否为 -nonzero。 -z 的意图也很明确 - 测试字符串是否具有 -zero 长度。我发现写 [ "$var" ][ ! "$var" ] 会让其他人感到困惑。起初看起来 $var[ ].

中有一些特殊的含义

I recently found this "bug" in my bash script

这不是错误,这是一个功能!

首先,你使用单括号。这意味着您正在使用 test 命令而不是 Bash-内置函数。来自手册:

test EXPRESSION or [ EXPRESSION ]: this exits with the status returned by EXPRESSION

-n STRING: the length of STRING is nonzero.

STRING: equivalent to -n STRING

source: man test

这应该可以回答您的问题。

此外:

! EXPRESSION: test returns true of EXPRESSION is false

-z STRING: test returns true if the length of STRING is zero.

这意味着 [ ! STRING ] 等同于 [ -z STRING ]