如何在 shell 脚本中使用和/或条件

如何在 shell 脚本中使用和/或条件

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,(RANDOM0.003% 的时间)...也会如此):

    if [ "$((a != 0 || b != 100))" -ne 0 ]; then...
    

    但是,如果变量的内容导致算术扩展因语法错误而失败,则会导致 shell 中止,因此您可能需要在子 shell 中运行它来解决这个问题。

    if ([ "$((a != 0 || b != 100))" -ne 0 ]); then
    

    如果变量的内容不在您的控制之下,您可能不应该使用该形式,因为那样会一个任意命令执行漏洞在许多贝壳中( bash, ksh, zsh) (例如值$alike x[$(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

相关内容