如何在Bash脚本中添加计时器?

7

你好!有没有办法在使用 Bash 的脚本中包含一个定时器(时间戳?或其他术语)?例如:每60秒钟,一个特定的函数检查互联网是否断开连接,如果是,则连接到wifi设备,反之亦然。简而言之,该程序会定时检查互联网连接。

任何建议/答案将不胜感激。=)

6个回答

18

简明版

while sleep 60; do
  if ! check_internet; then
    if is_wifi; then
       set_wired
    else
       set_wifi
    fi
  fi
done

使用睡眠本身作为循环条件,可以通过终止睡眠来跳出循环(例如,如果它是前台进程,则可以使用Ctrl-C)。

如果我们讨论的是几分钟或几小时的时间间隔,cron可能会更好,正如Montecristo所指出的那样。


我知道了.. 我会试一下这个。谢谢大家!我最好也看一下“man cron”。=) - Suezy
函数调用的时候不应该在结尾加括号。 - camh

5
您可能想要执行 man cron
或者如果您只想坚持使用bash,只需将函数调用放在循环内,并在迭代中添加 sleep 60

4
请看下面的脚本,您可以使用它。首先像这样将一个条目添加到您的cron作业中: $ sudo crontab -e * * * * * /path/to/your/switcher 这是一种简单的方法,连续每分钟ping一个活动的服务器,如果服务器无法访问,它将切换到下面定义的第二个路由器。
当然,还有更好的方法来利用这个问题。 $ cat > switcher
#!/bin/sh

route=`which route`
ip=`which ip`

# define your email here
mail="user@domain.tld"

# We define our pingable target like 'yahoo' or whatever, note that the host have to be 
# reachable every time
target="www.yahoo.com"

# log file
file="/var/log/updown.log"

# your routers here
router1="192.168.0.1"
router2="192.168.0.254"

# default router
default=$($ip route | awk '/default/ { print $3 }')

# ping command
ping -c 2 ${target}

if [ $? -eq 0 ]; then
   echo "`date +%Y%m%d-%H:%M:%S`: up" >> ${file}

else
   echo "`date +%Y%m%d-%H:%M:%S`: down" >> ${file}

   if [ ${default}==${router1} ]; then
       ${route} del default gw ${router1}
       ${route} add default gw ${router2}
   elif [ ${default}==${router2} ];  then
       ${route} del default gw ${router2}
       ${route} add default gw ${router1}
   fi
   # sending a notification by mail or may be by sms
   echo "Connection problem" |mail -s "Changing Routing table" ${mail}
fi

1
以上是笔误,应该是 "sudo crontab -e ..." 而不是 "sudo contab -e ..."。 - JJ.
这似乎是最佳解决方案,因为cron就是为这种任务设计的。在一些可重复的时间延迟内执行某些操作(例如脚本)。 - Jim
我认为脚本缺少自动检测默认路由的功能,但我认为我已经找到了它。 - Ali Mezgani
我真的认为我们必须教人如何钓鱼,因为最终使用的是CTRL+C CTRL+V... 在我看来 ^^ - Alberto Zaccagni

3
我喜欢 William 的答案,因为它不需要轮询。所以我基于他的想法实现了下面的脚本。它解决了控制必须返回到 shell 的问题。
#!/bin/sh

someproc()
{
        sleep $1
        return $2
}

run_or_timeout()
{
        timeout=$1
        shift

        {
                trap 'exit 0' 15
                "$@"
        } &
        proc=$!

        trap "kill $proc" ALRM
        {
                trap 'exit 0' 15
                sleep $timeout
                kill -ALRM $$
        } &
        alarm=$!

        wait $proc
        ret=$?

        # cleanup
        kill $alarm
        trap - ALRM
        return $ret
}

run_or_timeout 0 someproc 1 0
echo "exit: $? (expected: 142)"
run_or_timeout 1 someproc 0 0
echo "exit: $? (expected: 0)"
run_or_timeout 1 someproc 0 1
echo "exit: $? (expected: 1)"

1

您可以尝试以下方法,但它并不可靠:

#!/bin/sh
trap handle_timer USR1
set_timer() { (sleep 2; kill -USR1 $$)& } handle_timer() { printf "%s:%s\n" "计时器已过期" "$(date)"; set_timer }
set_timer while true; do sleep 1; date; done

这种技术的一个问题是,陷阱只有在当前任务返回到shell后才会生效(例如,将sleep 1替换为sleep 10)。如果shell大部分时间都在控制下(例如,如果它调用的所有命令都会快速终止),那么这可能有效。当然,一种选择是将所有内容都在后台运行。


0
创建一个 Bash 脚本,检查一次互联网连接是否中断,并将该脚本添加到一个每 60 秒运行一次的 crontab 任务中。

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