在Bash中否定多个条件

4

我知道这是一个简单的问题,但由于bash中挑剔的语法要求,我很难得到答案。我有以下脚本:

if ! [ [ -z "$1" ] || [ -z "$2" ] ]; then
  echo "both arguments are set!"
fi

当我没有输入任何参数运行时,会得到以下输出:
./test: line 3: [: -z: binary operator expected 
both arguments are set!

我没有期望任何输出 - 没有设置任何参数。我做错了什么?


尽量避免使用-n测试选项进行否定。 - Walter A
@9999999999999999999999999999999999999999999999999999999999999 正好相反。请查看Barmar的答案。 - Zloj
从布尔逻辑:¬(A v B) => ¬A ^ ¬B - Phylogenesis
@Zloj并不是真的,[[]]显然是一种更好的结构。仅仅因为你可以像barmar那样做,就不代表它更好... - 123
@999999999999999999999999999999虽然双括号也可以实现相同的功能,但单括号确保了可移植性、更易读和不容易混淆。那么双括号为什么会更好呢?您能详细说明一下为什么[[ ]]结构更好吗? - Zloj
@Zloj,它们是可移植的,仅此而已。它们在可读性方面并不更好,功能较少且需要引用所有内容。 - 123
3个回答

11

方括号在bash中不是组合结构。 [只是test命令的别名,参数按正常方式解析。而||是一个分隔命令的shell运算符。

如果要对多个命令进行分组,可以使用()子shell语法。

if ! ([ -z "$1" ] || [ -z "$2" ]);

或者使用{ }分组语法:

if ! { [ -z "$1" ] || [ -z "$2" ]; };

或者您可以使用单个调用带有其内置-o操作符的test:

if ! [ -z "$1" -o -z "$2" ]

我在第一次运行时犯了一个错误 - 这实际上并不适用于我。表达式总是返回true,并且随后的语句总是执行。也许我缺少您预期脚本的一部分 - 您能提供一个可工作的示例吗? - Jake
!的优先级高于||,因此您需要使用一个组(或更好的方法是,以更明智的方式重写逻辑)。 - Tom Fenech

8
< p > test shell内置命令[支持参数-a-o,分别代表逻辑AND和OR。

#!/bin/sh 

if [ -n "$1" -a -n "$2" ]
then echo "both arguments are set!"
fi

这里我使用 -n 来检查字符串的长度是否非零,而不是使用 -z 来表示它们是零长度,因此必须用 ! 取反。

"-n string 如果字符串的长度非零,则为真。"

"-z string 如果字符串的长度为零,则为真。"

如果您正在使用 bash,它还支持更强大的测试类型 [[]],可以使用布尔运算符 ||&&

#!/bin/bash 

if [[ -n "$1" && -n "$2" ]]
then echo "both arguments are set!"
fi

在评论中提到,这些示例都没有展示如何在Shell中否定多个测试条件,下面是一个能够实现的示例:

#!/bin/sh 

if [ ! -z "$1" -a ! -z "$2" ]
then echo "both arguments are set!"
fi

在我的原始问题中,我将这两个测试放在不同的括号对中。这样做的目的是因为我可能会有更复杂的表达式,其中包含自己的运算符,并且能够使用括号或圆括号指定优先级会很好。Bash 对此也很挑剔。您能否解释一下如何像原始问题那样将多个子条件分组在一起,以便可以将单个逻辑运算符应用于复合表达式? - Jake
在您的倒数第二个示例中,我认为 [[ -n "$1" || -n "$2" ]] 应该改为 [[ -n "$1" && -n "$2" ]](也可以删除引号)。 - Tom Fenech
已更新以反映您的建议,Fenech博士。 - user4832408

6

记住(或学习!)[不是shell语法的一部分,而是一个命令。

如果您想将多个命令组合在一起,则应使用{ }

if ! { [ -z "$1" ] || [ -z "$2" ]; }

请注意,解析器在关闭 } 之前期望看到换行符或分号。
顺便说一句,我会避免使用否定,并在此处使用 &&
if [ -n "$1" ] && [ -n "$2" ]

既然你指定了,那么你也可以利用增强测试结构:

if [[ -n $1 && -n $2 ]]

你可以把“and”放在结构体中间,而不是创建两个实例。 - 123

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接