bash 中的复合逻辑测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10486263/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:13:01  来源:igfitidea点击:

Compound logical tests in bash

bashtesting

提问by bob.sacamento

A question about bash ....

关于bash的问题....

I wrote a little code to check whether a year is a leapyear. The relevant part looks like:

我写了一些代码来检查一年是否是闰年。相关部分如下所示:

if [ $testnum4 -eq 0 -a $testnum100 -ne 0 ] || [ $testnum400 -eq 0 ]
then
  echo 0
fi

Well, this code actually works. My problem is that I'm still not quite sure what I was doing. Just to see what would happen, I have tried several variations on this: enclosing the entire test expression in square backets, using &&where I have -aand -owhere I have ||, etc. Nothing works except for the one expression that I wrote above. I stumbled on it, and I'm glad I did, but the next time I have to do something like this, I would like to know what I am doing.

好吧,这段代码确实有效。我的问题是我仍然不太确定我在做什么。只是为了看看会发生什么,我已经尝试了几种变体:将整个测试表达式包含在方形 backets 中,使用&&where I have-a-owhere I have||等。除了我上面写的一个表达式之外,没有任何效果。我偶然发现了它,我很高兴我做到了,但是下次我必须做这样的事情时,我想知道我在做什么。

So: Anyone have a quick explanation of how compound tests work in bash? or a pointer to a good resource on this topic?

所以:有人对复合测试在 bash 中的工作方式有一个快速的解释吗?或指向有关此主题的良好资源的指针?

Thanks.

谢谢。

Here's a code that failed:

这是一个失败的代码:

let testnum4=%4
let testnum100=%100
let testnum400=%400

if [ $testnum4 -eq 0 && $testnum100 -ne 0 ] -o [ $testnum400 -eq 0 ]
then
  echo 0
fi

回答by David W.

Little note of interest: The square braces are actually a Unix command. See if there's a file called /bin/[or /usr/bin/[on your system. In fact, try this:

有趣的一点:方括号实际上是一个 Unix 命令。查看您的系统上是否有调用的文件/bin/[或文件/usr/bin/[。事实上,试试这个:

$ ls i-il /bin[ /bin/test
571541 -r-xr-xr-x  2 root  wheel  43120 Aug 17  2011 /bin/[
571541 -r-xr-xr-x  2 root  wheel  43120 Aug 17  2011 /bin/test

That first number is the i-node number. You see that /bin/[and /bin/testare hard linked to each other. They're the same program.

第一个数字是 i 节点编号。你看到了,/bin/[并且/bin/test彼此很难联系起来。他们是同一个程序。

I'll get back to the significance of this a bit later...

稍后我会回到这一点的重要性......



In BASH and other Bourne type shells, the ifcommand merely runs the command, and if the command returns an exit code of 0, it executes the commands in the ifclause. If the command does not return an exit code of 0, it skips the commands in the ifclause and executes the commands in the elseclause if it exists.

在 BASH 和其他 Bourne 类型的 shell 中,if命令只是运行命令,如果命令返回退出代码0,则执行if子句中的命令。如果该命令不返回退出代码0,则跳过该if子句中的命令并执行该子句中的命令(else如果存在)。

Thus, this is also valid:

因此,这也是有效的:

if sleep 2
then
   echo "That was a good nap!"
fi

Your computer executes the sleep 2command which (if the sleep command exists) will return a zero exit code and continue to echo That was a good nap!.

您的计算机执行该sleep 2命令(如果存在 sleep 命令)将返回零退出代码并继续回显这是一个很好的小睡!.

That's all the ifcommand really does. It runs the given command and examines the exit code.

这就是if命令的全部作用。它运行给定的命令并检查退出代码。



Now, back to the [...

现在,回到[...

You might want to look at the manpage for the testcommand. You can see that the testcommand seems to have many of the same type of tests as the [...]in the if statement. In fact, in the original Bourne shell (which BASH is derived from) these are the same command structure:

您可能需要查看test命令的联机帮助页。您可以看到该test命令似乎有许多[...]与 if 语句中的测试类型相同的测试。事实上,在原始的 Bourne shell(BASH 派生自)中,这些是相同的命令结构:

if test -f $my_file
then
    echo "File $my_file exists"
else
    echo "There is no file $my_file"
fi

if [ -f $my_file ]
then
    echo "File $my_file exists"
else
    echo "There is no file $my_file"
fi

In fact, in the original Bourne shell, you had to use the testcommand and not the square brackets.

事实上,在最初的 Bourne shell 中,您必须使用test命令而不是方括号。



So, back to your original question. The -aand -oare parameters for the test command (see the testmanpage. For example, your ifstatement could have been written as this:

所以,回到你最初的问题。该-a-o是测试命令(参见参数test手册页例如,你的。if语句可以写成这样:

if test $testnum4 -eq 0 -a $testnum100 -ne 0 || test $testnum400 -eq 0
then
   echo 0
fi

However, the &&and ||are not test command parameters, so they can't be used inside the test command.

但是,&&||不是测试命令参数,因此它们不能在测试命令中使用。

Note that [is a built in command in BASH, so BASH does not execute /bin/[as the original Bourne shell would have. However, it is still a command much like echois a built in command in BASH although /bin/echoalso still exists.

请注意,这[是 BASH 中的内置命令,因此 BASH 不会/bin/[像原始 Bourne shell 那样执行。然而,它仍然echo是一个很像BASH 中的内置命令的命令,尽管它/bin/echo仍然存在。

回答by Paused until further notice.

The correct way to do integer comparisons in Bash is to use double parentheses:

在 Bash 中进行整数比较的正确方法是使用双括号:

if (( (testnum4 == 0 && testnum100 != 0) || testnum400 == 0 ))

回答by Todd A. Jacobs

The Algorithm

算法

The algorithm to check for leap years is (in pseudo code):

检查闰年的算法是(在伪代码中):

if (YEAR modulo 400):
    LEAP_YEAR = true
elseif (YEAR modulo 4) and not (YEAR modulo 100):
    LEAP_YEAR = true
else
    LEAP_YEAR = false
endif

I'd recommend against using over-clever solutions, and stick with something more readable. See the Bash Beginner's Guidefor a working example of a leap year test using nested if statements. It uses the deprecated $[]arithmetic expression, so just replace the arithmetic expressions with $(( ))and you can see how it's supposed to work.

我建议不要使用过于聪明的解决方案,并坚持使用更具可读性的解决方案。有关使用嵌套 if 语句的闰年测试的工作示例,请参阅Bash 初学者指南。它使用不推荐使用的$[]算术表达式,因此只需将算术表达式替换为$(( )),您就可以看到它应该如何工作。

How the OPs Code Works

OP 代码的工作原理

In the OPs updated code example, the values are separate variables built from a positional paramater. So, the modulo arithmetic is being performed on the variables before they are evaluated in the conditional statements. After that, the if statement says:

在 OP 更新的代码示例中,这些值是根据位置参数构建的单独变量。因此,在条件语句中评估变量之前,对变量执行模运算。之后,if 语句说:

if (first_expression returns true) or (second_expression returns true):
    echo 0
endif

The single-square brackets are simply a shell builtin that performs the same as the testcommand, which evaluates an expression and returns an exit status where zero is truth. See help \[or man testfor more information.

单方括号只是一个 shell 内置函数,它执行与test命令相同的命令,它计算表达式并返回一个退出状态,其中零为真。查看help \[man test了解更多信息。

Building a Better Mousetrap

制作更好的捕鼠器

While I and other posters have explained why the OPs code works, it seems that part of the OPs goal is to place the entire leap year test inside a single conditional. Here's a Bash shell function that will do this, and let you test the result by inspecting the exit status.

虽然我和其他发帖人已经解释了为什么 OP 代码有效,但似乎 OP 目标的一部分是将整个闰年测试置于单个条件中。这是一个 Bash shell 函数,可以执行此操作,并让您通过检查退出状态来测试结果。

# function returns exit status of arithmetic expression
leap_year () { 
    ((  % 400 == 0 || ( % 4 == 0 &&  % 100 != 0) ))
}

You can test the function at the prompt:

您可以在提示符下测试该功能:

$ leap_year 2011; echo $?
1
$ leap_year 2012; echo $?
0
$ leap_year 2013; echo $?
1

For more information on the (( ))arithmetic expression, see the Conditional Constructssections of the Bash Reference Manual.

有关(( ))算术表达式的更多信息,请参阅Bash 参考手册的条件构造部分。

回答by Samveen

In bash(actually most shells) iftakes a command/set of commands and evaluates the thensection if the last command returns true (zero exit code), otherwise it evaluates the elif/elsesections (elifis treated in a manner similar to else).

在 bash(实际上是大多数 shell)中ifthen如果最后一个命令返回 true(零退出代码),则接受一个命令/一组命令并评估该部分,否则它评估elif/else部分(elif以类似于 else 的方式处理)。

Now about the [[. This is like the testcommand, but with greater test coverage. However it has the limitation that it can evaluate only one condition at a time, so it doesn'taccept -oor -a. You might want to look at [as a true alias of test. As for the ||and &&these are control operators that evaluate the next command if the previous command returns false (non-zero exit code) or true (zero exit code) respectively. The use of these 2 is to chain commands together (especially [[).

现在关于[[. 这类似于test命令,但具有更大的测试覆盖率。但是它有一个限制,它一次只能评估一个条件,所以它接受-o-a。您可能希望将其[视为test. 至于 the||&&这些是控制运算符,如果上一个命令分别返回 false(非零退出代码)或 true(零退出代码),它们会评估下一个命令。这两个的用途是将命令链接在一起(尤其是[[)。

As for the above if, it executes 2 commands:

至于上面的if,它执行了2条命令:

  • First: [ $testnum4 -eq 0 -a $testnum100 -ne 0 ]
  • Second: [ $testnum400 -eq 0 ]
  • 第一的: [ $testnum4 -eq 0 -a $testnum100 -ne 0 ]
  • 第二: [ $testnum400 -eq 0 ]

If the first command succeeds, the if executes the thensection. If the first command fails, then the second is executed. If the second succeeds, then the body is executed, else ifdoes nothing.

如果第一个命令成功,则 if 执行该then部分。如果第一个命令失败,则执行第二个命令。如果第二个成功,则执行主体,否则if不执行任何操作。

As for a good bash resource, you might want to visit The Bash Wiki

至于一个好的 bash 资源,你可能想访问The Bash Wiki