如何在指定时间段内运行bash脚本中的命令?

3
假设我只需要在上午11点10分到下午2点30分之间运行“command”。如何在Bash脚本中实现这个功能?
类似下面的伪代码:
#!/bin/bash
while(1) {
    if ((currentTime > 11:10am) && (currentTime <2:30pm)) {
        run command;
        sleep 10;
    }
}
3个回答

7

其他回答忽略了一个事实,当一个数字以0开头时,Bash会将其解释为8进制。 所以,例如,在早上9点时,date '+%H%M'将返回0900,这是Bash中一个无效的数字。(现在不再是这样了)。

一个合适且安全的解决方案,使用现代Bash:

while :; do
    current=$(date '+%H%M') || exit 1 # or whatever error handle
    (( current=(10#$current) )) # force bash to consider current in radix 10
    (( current > 1110 && current < 1430 )) && run command # || error_handle
    sleep 10
done

如果您能接受第一次运行时可能出现的10秒延迟,那么可以将其缩短一些:

while sleep 10; do
    current=$(date '+%H%M') || exit 1 # or whatever error handle
    (( current=(10#$current) )) # force bash to consider current in radix 10
    (( current > 1110 && current < 1430 )) && run command # || error_handle
done

完成!


看一下:

$ current=0900
$ if [[ $current -gt 1000 ]]; then echo "does it work?"; fi
bash: [[: 0900: value too great for base (error token is "0900")
$ # oooops
$ (( current=(10#$current) ))
$ echo "$current"
900
$ # good :)

正如xsc在评论中指出的那样,它可以与古老的[内置命令一起使用...但那已经是过去的事情了:)。

1
对我来说,单个 [] 运行良好,即 [ $current -gt 1000 ] 不会抛出错误。 - xsc
是的,它可以很好地与外部测试命令(及其分支[)一起使用,但无法与Bash内部指令一起使用。我不知道为什么 :/[ ~]$ test "09" -eq "9" && echo "ok" 结果是 ok[ ~]$ [[ 09 -eq 9 ]] && echo "ok" 结果是 -bash: [[: 09: value too great for base (error token is "09") - Idriss Neumann
1
@IdrissNeumann 当你在Bash中使用test[时,你使用的是bash内置命令,而不是外部命令。对于外部命令,你需要使用command testcommand [或在之前使用enable -n testenable -n [ - gniourf_gniourf
@gniourf_gniourf:感谢您的澄清。我现在想更新我的教程^^(无论如何,保护其操作数的故事在所有情况下都是正确的)。 - Idriss Neumann

2
你可以尝试类似以下的方法:

currentTime=$(date "+%H%M")
if [ "$currentTime" -gt "1110" -a "$currentTime" -lt "1430" ]; then
    # ...
fi
# ...

或者:
currentTime=$(date "+%H%M")
if [ "$currentTime" -gt "1110" ] && [ $currentTime -lt "1430" ]; then
    # ...
fi
# ...

或者:
currentTime=$(date "+%H%M")
[ "$currentTime" -gt "1110" ] && [ "$currentTime" -lt "1430" ] && {
    # ...
}
# ... 

详情请参见 man date。您还可以使用cron任务来执行超过11:30运行此脚本的操作。

NB: 对于循环,您可以使用类似以下内容的代码:

while [ 1 ]; do 
    #...
done

或者:
while (( 1 )); do 
    #...
done

1
应该不是 $(date +"%M%S") 吧?你正在检查分钟和秒钟,正确的应该是 +"%H%M" - xsc
@AlexeiChirknuov 不用谢,别忘了将此主题标记为已解决 ;) - Idriss Neumann

0

您可以使用date +"%H%M"创建一个描述当前时间的4位数字。我认为这可以用于与其他时间(以24小时格式)进行数字比较:

while [ 1 ]; do
    currentTime=$(date +"%H%M");
    if [ "$currentTime" -gt 1110 ] && [ "$currentTime" -lt 1430 ]; then
        ...
    fi
    sleep 10;    # probably better to have this outside the if-statement
done

如果您想处理包括午夜的时间跨度,只需将&&替换为||


如果您使用外部测试命令(或其分支[),则必须用双引号保护操作数。有关更多详细信息,请参见此答案:https://dev59.com/_WIk5IYBdhLWcg3wFKlK#19598570 - Idriss Neumann
这对我来说似乎运行良好。除非“date”未返回任何内容,否则这真的是一个问题吗?或者这取决于我使用的Bash版本? - xsc
1
你的 date 命令没有返回带空格的值,这没有问题。但是这是一个应该一直遵循的好习惯。否则,如果你不想保护你的操作数,可以使用内部 Bash 指令 [[ 而不是 [。请参考我之前提供的链接以获取更多信息。 - Idriss Neumann
只是为了确保:我不必在这里做,但这是一个好的实践吗?当然,我会修改我的答案。谢谢! - xsc
2
"@xsc 使用适当的引号也可以使您的程序运行得更快(取决于shell实现),因为shell不需要在适当引用的字符串上运行字符串拆分和通配符扩展。" - Charles Duffy
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接