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

【讨论】:

很棒的帖子,括号中的总结很理想。 最好用==区分比较和赋值变量(也就是= 您可以强调单括号在双括号内部和外部具有完全不同的语义。 (因为您首先明确指出了 subshel​​l 语义,但随后仅作为条件表达式的一部分提及分组语义。当我查看您的惯用示例时,让我感到困惑。) 哦,我的意思是单(圆)括号,抱歉造成混淆。 [[ $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 中的简单逻辑运算符的主要内容,如果未能解决你的问题,请参考以下文章

python中的简单while循环及逻辑运算符

19.自学Linux之路:bash条件的逻辑运算与bash编程之字符测试

在 if elif else 语句中具有逻辑与和 ors 的 Bash 脚本

bash特性之逻辑运算和shell脚本的编写

shell之算数运算符逻辑运算符关系运算符布尔运算符文件测试运算符

linux基础--Bash逻辑控制语句