Bash 中的简单逻辑运算符
Posted
技术标签:
【中文标题】Bash 中的简单逻辑运算符【英文标题】:Simple logical operators in Bash 【发布时间】:2011-09-10 08:34:12 【问题描述】:我有几个变量,我想检查以下条件(用文字写出来,然后我尝试 bash 脚本失败):
if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then
do something
done.
在我失败的尝试中,我想出了:
if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) );
then
scale=0.05
fi
【问题讨论】:
【参考方案1】:非常接近
if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]];
then
scale=0.05
fi
应该可以。
分解
[[ $varA -eq 1 ]]
是整数比较
$varB == 't1'
是一个字符串比较。 否则,我只是正确地对比较进行分组。
双方括号分隔条件表达式。而且,我发现以下是关于这个主题的好读物:"(IBM) Demystify test, [, [[, ((, and if-then-else"
【讨论】:
只是为了确定:'t1'
中的引用是不必要的,对吧?因为与双括号中的算术指令相反,其中t1
将是一个变量,双括号 中的条件表达式中的t1
只是一个文字字符串。即[[ $varB == 't1' ]]
与[[ $varB == t1 ]]
完全相同,对吧?【参考方案2】:
您所写的内容实际上几乎可以工作(如果所有变量都是数字,它会工作),但这根本不是一种惯用的方式。
(…)
括号表示subshell。它们里面的东西不像许多其他语言那样表达。它是一个命令列表(就像外括号一样)。这些命令在单独的子进程中执行,因此括号内执行的任何重定向、赋值等对括号外都没有影响。
带前导美元符号的$(…)
是command substitution:括号内有一个命令,该命令的输出用作命令行的一部分(在额外扩展之后,除非替换在双精度引号,但那是 another story)。
…
大括号就像括号一样,它们对命令进行分组,但它们只影响解析,而不影响分组。程序 x=2; x=4; ; echo $x
打印 4,而 x=2; (x=4); echo $x
打印 2。(大括号需要在它们周围有空格并在结束前使用分号,而括号则不需要。这只是一个语法怪癖。)
带有前导美元符号的$VAR
是parameter expansion,扩展为变量的值,并可能进行额外的转换。
((…))
双括号包围 arithmetic instruction,即整数计算,其语法类似于其他编程语言。这种语法主要用于赋值和条件。
算术表达式$((…))
使用相同的语法,它扩展为表达式的整数值。
[[ … ]]
双括号包围conditional expressions。条件表达式大多建立在operators 之上,例如-n $variable
用于测试变量是否为空,-e $file
用于测试文件是否存在。还有字符串相等运算符:"$string1" == "$string2"
(注意右边是一个模式,例如[[ $foo == a* ]]
测试$foo
是否以a
开头,而[[ $foo == "a*" ]]
测试$foo
是否正好是a*
),以及熟悉的!
、&&
和||
运算符用于否定、连接和析取以及用于分组的括号。请注意,每个运算符周围都需要一个空格(例如[[ "$x" == "$y" ]]
,而不是[[ "$x"=="$y" ]]
;
的字符(例如[[ -n $foo ]]
,不是[[-n $foo]]
[ … ]
单括号是条件表达式的另一种形式,具有更多怪癖(但更旧且更便携)。暂时不要写;当您找到包含它们的脚本时开始担心它们。
这是用 bash 编写测试的惯用方式:
if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then
如果您需要移植到其他 shell,这就是方法(注意每个单独的测试周围的附加引号和单独的括号集,以及使用传统的 =
运算符而不是 ksh/bash/zsh ==
变体):
if [ "$varA" = 1 ] && [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; ; then
【讨论】:
很棒的帖子,括号中的总结很理想。 最好用==
区分比较和赋值变量(也就是=
)
您可以强调单括号在双括号内部和外部具有完全不同的语义。 (因为您首先明确指出了 subshell 语义,但随后仅作为条件表达式的一部分提及分组语义。当我查看您的惯用示例时,让我感到困惑。)
哦,我的意思是单(圆)括号,抱歉造成混淆。 [[ $varA = 1 && ($varB = "t1" || $varC = "t2") ]]
中的那些不启动子进程,尽管第一个要点明确指出:“[括号] 里面的内容不是一个表达式,就像许多其他语言一样”——但它肯定是这里!这对于经验丰富的 bash 奇才来说可能是显而易见的,但对我来说甚至都不是。可能会出现混淆,因为单括号可以在if
语句中使用,而不是在双括号内的表达式中。
@protagonist ==
并不比=
更“惯用”。它们具有相同的含义,但 ==
是一个 ksh 变体,也可用于 bash 和 zsh,而 =
是可移植的。使用==
并没有任何优势,而且在普通的 sh 中也不起作用。【参考方案3】:
if ([ $NUM1 == 1 ] || [ $NUM2 == 1 ]) && [ -z "$STR" ]
then
echo STR is empty but should have a value.
fi
【讨论】:
你能告诉我 -z 标志在 bash 中有什么用吗?【参考方案4】:一个非常便携的版本(甚至是遗留的 bourne shell):
if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then do-something
fi
这具有最多只运行一个子进程(即进程[
)的额外质量,无论外壳风格如何。
如果变量包含数值,则将 =
替换为 -eq
,例如
3 -eq 03
是真的,但是
3 = 03
是假的。 (字符串比较)
【讨论】:
【参考方案5】:这里是 if-then-else 语句的简短版本的代码:
( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"
注意以下几点:
||
和 &&
内的操作数 if 条件(即圆括号之间)是逻辑操作数(或/和)
||
和 &&
操作数在 if 条件均值 then/else 之外
实际上声明说:
if (a=1 or b=2) then "ok" else "nok"
【讨论】:
括号( ... )
创建一个子shell。可能想改用大括号 ...
。在子 shell 中创建的任何状态在调用者中都不可见。以上是关于Bash 中的简单逻辑运算符的主要内容,如果未能解决你的问题,请参考以下文章
19.自学Linux之路:bash条件的逻辑运算与bash编程之字符测试
在 if elif else 语句中具有逻辑与和 ors 的 Bash 脚本