我if
在脚本中有一个声明。
它看起来像这样:
if [ "$a" != "0" -a "$b" != "100" ]; then
#some commands here
如果我没记错的话,如果两个条件都成立,上面的行就会起作用。
现在,我该如何测试任何一个执行前一个或两个条件都为真some commands
?
答案1
标准(POSIX sh 和实用程序)规范的清晰方式是:
细绳比较:
if [ "$a" != 0 ] || [ "$b" != 100 ]; then...
十进制整数比较(0100 是 100,但是否忽略前导空格取决于实现)。
if [ "$a" -ne 0 ] || [ "$b" -ne 100 ]; then...
整数比较(0x64、0144 是 100(对于八进制的某些 shell 必须启用 POSIX 模式)。根据 shell 100.0、1e2、50+50,(
RANDOM
0.003% 的时间)...也会如此):if [ "$((a != 0 || b != 100))" -ne 0 ]; then...
但是,如果变量的内容导致算术扩展因语法错误而失败,则会导致 shell 中止,因此您可能需要在子 shell 中运行它来解决这个问题。
if ([ "$((a != 0 || b != 100))" -ne 0 ]); then
如果变量的内容不在您的控制之下,您可能不应该使用该形式,因为那样会一个任意命令执行漏洞在许多贝壳中(
bash
,ksh
,zsh
) (例如值$a
likex[$(reboot)]
)。
您选择哪一个取决于变量的内容以及您希望它们的内容。如果您知道它们包含规范形式的十进制整数,则所有 3 个都是等效的。
无论如何,请避免使用-a
/-o
test
运算符在一般情况下已被弃用且不可靠(如果您可以控制变量的内容,则不在这里)。
答案2
使用算术求值和括号以避免歧义:
if (( ($a != 0) || ($b != 100) )); then
# some commands
或者,如果您也想处理字符串,请使用[[
.
答案3
[ "$((a||b^100))" -eq 1 ] && some commands
shell 的数学扩展将通过将表达式计算为 1(真)或 0(假)来处理布尔&&
AND ||
OR 和NOT 条件。!
它也会处理按位&
AND |
OR 和^
XOR 运算符,但显然这些运算符不一定会得到 0 或 1,尽管按位表达式可以用作布尔 eval 的字段,就像这里一样。有趣的是,shell 甚至可以进行旋转~
和<<
左右>>
SHIFT 操作。
因此,如果a
为 true ORb^100
为 true,则扩展求值为 1,匹配比较-eq
[
测试]
,并且 shell 继续求值的其余部分&& some commands
。
以这种方式评估/比较整数通常比尝试串在一起更容易......
...和二元
-a
初选-o
和运算(
符)
已被标记为过时。(许多使用它们的表达式是由语法模糊定义的,具体取决于正在评估的特定表达式。)
(^直接引用test
规范)
即使这可行,在正式加入之前,4 也是你能达到的极限未指定领土。
过去,我经常发现应用一些抽象很有用,例如:
math(){ return "$((!($1)))"; }
...可以像...一样使用
math 'a||b^100' && some commands
虽然这并不是我的想法:我实际上是从 POSIX 规范中得到的XRAT 基本原理部分:
...[i]得出的结论是该
test
命令([
)对于大多数关系算术测试来说已经足够了,并且在 shell 中涉及复杂关系表达式的测试很少见,但仍然可以通过测试"$(())"
其自身的值来满足。例如:
# a complicated relational expression
while [ "$(( (($x + $y)/($a * $b)) < ($foo*$bar) ))" -ne 0 ]
...或者更好的是,具有许多复杂关系表达式的罕见脚本可以定义这样的函数...
val() { return "$((!$1))"; }
(不过,我"
在上面添加了引号。那些家伙有什么问题吗?)
答案4
比我上面看到的更简单的答案。
if [ "$a" != "0" -o "$b" != "100" ]; then