关于bash的问题......
我写了一些代码来检查一年是否是一个年级。相关部分如下:
if [ $testnum4 -eq 0 -a $testnum100 -ne 0 ] || [ $testnum400 -eq 0 ]
then
echo 0
fi
嗯,这段代码确实有效。我的问题是我还不太确定我在做什么。只是为了看看会发生什么,我已经尝试了几种变体:将整个测试表达式用方括号括起来,使用&&
我有-a
和-o
我{{1}除了我上面写的一个表达式,什么都没有用。我偶然发现它,我很高兴我做到了,但下次我必须做这样的事情,我想知道我在做什么。
所以:任何人都能快速解释复合测试在bash中的运作方式吗?或指向这个主题的好资源的指针?
感谢。
这是失败的代码:
||
答案 0 :(得分:16)
感兴趣的小方块:方括号实际上是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
第一个数字是索引节点号。您发现/bin/[
和/bin/test
很难相互关联。他们是同一个计划。
稍后我会回到这个意义......
在BASH和其他Bourne类型的shell中,if
命令只运行命令,如果命令返回退出代码0
,它将执行if
子句中的命令。如果该命令未返回0
的退出代码,则会跳过if
子句中的命令,并执行else
子句中的命令(如果存在)。
因此,这也是有效的:
if sleep 2
then
echo "That was a good nap!"
fi
您的计算机执行sleep 2
命令(如果存在睡眠命令)将返回零退出代码并继续回显这是一个很好的午睡!。
这就是所有if
命令真的。它运行给定的命令并检查退出代码。
现在,回到[
...
您可能需要查看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
事实上,在最初的Bourne shell中,你必须使用test
命令而不是方括号。
所以,回到你原来的问题。 -a
和-o
是测试命令的参数(请参阅test
联机帮助页。例如,您的if
语句可能已写为:
if test $testnum4 -eq 0 -a $testnum100 -ne 0 || test $testnum400 -eq 0
then
echo 0
fi
但是,&&
和||
不是测试命令参数,因此不能在测试命令中使用它们。
请注意,[
是BASH中的内置命令,因此BASH不会像原始Bourne shell那样执行/bin/[
。但是,它仍然是一个命令,就像echo
是BASH中的内置命令一样,尽管/bin/echo
仍然存在。
答案 1 :(得分:3)
在Bash中进行整数比较的正确方法是使用双括号:
if (( (testnum4 == 0 && testnum100 != 0) || testnum400 == 0 ))
答案 2 :(得分:1)
检查闰年的算法是(伪代码):
if (YEAR modulo 400):
LEAP_YEAR = true
elseif (YEAR modulo 4) and not (YEAR modulo 100):
LEAP_YEAR = true
else
LEAP_YEAR = false
endif
我建议不要使用过于聪明的解决方案,并坚持使用更具可读性的东西。有关使用嵌套if语句的闰年测试的工作示例,请参阅Bash Beginner's Guide。它使用已弃用的$[]
算术表达式,因此只需将算术表达式替换为$(( ))
,您就可以看到它应该如何工作。
在OP更新的代码示例中,值是从位置参数构建的单独变量。因此,在条件语句中计算变量之前,对变量执行模运算。之后,if语句说:
if (first_expression returns true) or (second_expression returns true):
echo 0
endif
单方括号只是一个内置的shell,它执行与test
命令相同的操作,该命令用于计算表达式并返回退出状态,其中零是真值。有关详细信息,请参阅help \[
或man test
。
虽然我和其他海报已经解释了为什么OP代码有效,但似乎OP的部分目标是将整个闰年测试放在一个条件中。这是一个Bash shell函数,可以执行此操作,并让您通过检查退出状态来测试结果。
# function returns exit status of arithmetic expression
leap_year () {
(( $1 % 400 == 0 || ($1 % 4 == 0 && $1 % 100 != 0) ))
}
您可以在提示符下测试该功能:
$ leap_year 2011; echo $?
1
$ leap_year 2012; echo $?
0
$ leap_year 2013; echo $?
1
有关(( ))
算术表达式的更多信息,请参阅Bash参考手册的Conditional Constructs部分。
答案 3 :(得分:0)
在bash中(实际上是大多数shell)if
接受命令/命令集并在最后一个命令返回true(零退出代码)时评估then
部分,否则它会计算{{1 } / elif
部分(else
的处理方式与其他方式类似)。
现在关于elif
。这类似于[[
命令,但测试覆盖范围更广。但是它的局限性在于它一次只能评估一个条件,因此不接受 -o 或 -a 。您可能希望将test
视为[
的真正别名。对于test
和||
,如果前一个命令分别返回false(非零退出代码)或true(零退出代码),则这些控制操作符将评估下一个命令。这些2的使用是将命令链接在一起(尤其是&&
)。
对于上面的if,它执行2个命令:
[[
[ $testnum4 -eq 0 -a $testnum100 -ne 0 ]
如果第一个命令成功,则if执行[ $testnum400 -eq 0 ]
部分。如果第一个命令失败,则执行第二个命令。如果第二个成功,则执行正文,否则then
不执行任何操作。
对于好的bash资源,您可能想访问The Bash Wiki