我使用了来自的解决方案这个答案在我正在编写的脚本中,但它似乎对我不起作用。我使用的是 Bash 5。这是一个简化的测试用例,我希望该do_thing
函数在 5 的倍数的分钟内被调用(除非$min
和$minutes
相同,因为在真实的脚本中,我在主程序do_thing
开始时触发循环),但运行它也会触发这些倍数 + 1,所以显然我在某处有一点逐一或数学错误,但我没有看到它。有任何想法吗?
#!/usr/bin/env bash
minutes=6
sec=00
min="$minutes"
do_thing() {
echo 'done thing'
}
while [ "$min" -ge 0 ]; do
remainder=$(( min % 5 ))
# TODO: this is broken
[ "$remainder" -eq 0 ] && [ "$min" -ne "$minutes" ] && do_thing
while [ $sec -ge 0 ]; do
echo "$min $sec"
((sec=sec-1))
sleep 1
done
sec=59
((min=min-1))
done
答案1
set -x
调试任何 bash 脚本的第一件事就是在最顶部添加。这将让您看到脚本正在做什么、循环的每次迭代中的每个测试是什么样子等等。
这就是我要放的地方:
#!/usr/bin/env bash
# NOTE: Remove or comment the below line when you're done debugging!
set -x
minutes=6
sec=00
...
在调试时遍布echo "myvar = $myvar"
整个代码还可以帮助您跟踪脚本中关键点的变量值,以便您可以将其与您认为应该的值进行比较。
你逻辑中的缺陷是,一旦你得到了让你退出“分钟计数器”循环的条件,你立即将 min 减少 1所以当你重新计算余数时,你总是会少一。你正在减少你的“计数器”前你用它来进行你想要的计算!
从逻辑上讲,您想要测试秒= 0,然后计算余数,然后设置下一个循环:
#!/usr/bin/env bash
#set -x
minutes=6
sec=00
min="$minutes"
do_thing() {
echo 'done thing'
}
while [ "$min" -ge 0 ]; do
while [ $sec -ge 0 ]; do
echo "$min $sec"
((sec=sec-1))
sleep 1
done
remainder=$(( min % 5 ))
# Added echo for debugging
echo "remainder = $remainder"
[ "$remainder" -eq 0 ] && [ "$min" -ne "$minutes" ] && do_thing
sec=59
((min=min-1))
done
这里还有另一件事很突出——是非常小心使用&&
and ||
- 它们对于快速和肮脏来说很好,但是对于复杂的逻辑它们可以欺骗你!
这些逻辑运算符是不是适当测试的替代品,即使他们这样做有时- 与使用测试的一个区别if []; then...
是它们会默默地消耗您的退出代码。仔细阅读它们,并且不要连续使用其中多个,而不使用它们()
来强制执行您想要的操作顺序。
如果您想采纳我的建议并避免&&
在这里,这里有一种方法(嵌套的 `if 是另一种方法,但如果不需要,我宁愿不使用它们):
...
remainder=$(( min % 5 ))
# Added echo for debugging
echo "remainder = $remainder"
if ([ "$remainder" -eq 0 ] && [ "$min" -ne "$minutes" ]); then
do_thing
fi
sec=59
((min=min-1))
...