如何优雅地停止Bash脚本中的无限循环?

8
我需要每隔X秒运行一次应用程序,然而cron并不支持以秒为单位的方式。因此我编写了一个无限循环的bash脚本,在其中使用X秒间隔。

当我需要手动停止运行中的脚本时,我希望能够在正确的方式下停止。即让应用程序完成当前功能并且不再进入下一次循环。

您有任何想法可以实现这一点吗?我考虑传递参数,但我无法找到如何向正在运行的脚本传递参数。

4个回答

26

您可以捕获一个信号,比如说SIGUSR1:

echo "My pid is: $$"
finish=0
trap 'finish=1' SIGUSR1

while (( finish != 1 ))
do
    stuff
    sleep 42
done

然后,当你想在下一次迭代时退出循环:

kill -SIGUSR1 pid

pid为脚本的进程ID时,如果信号在睡眠期间被触发,它将会醒来(睡眠会一直持续到任何信号发生)。


2

您可以通过文件传递一些参数。在每次迭代中,您可以读取此文件并查看运行条件是否已更改。


1
如果您需要进行一些清理工作,以下结构可能是合适的。按照cdarke答案中所示使用kill命令。
#===============================================================
#  FUNCTION DEFINITIONS
#===============================================================
# . . .

#===  FUNCTION  ================================================
#          NAME:  cleanup
#   DESCRIPTION:  
#===============================================================
cleanup ()
{
  # wait for active children, remove empty logfile, ..., exit
  exit 0
} # ----------  end of function cleanup  ----------

#===============================================================
#   TRAPS
#===============================================================
trap  cleanup SIGUSR1

#===============================================================
#   MAIN SCRIPT
#===============================================================
echo -e "Script '$0' / PID ${$}"

while : ; do                                # infinite loop
  # . . .
  sleep 10
done
# . . .

#===============================================================
#   STATISTICS / CLEANUP
#===============================================================
cleanup

1

之前发布的陷阱解决方案适用于大型循环,但针对您只需要循环单个或几个命令的普通情况,这种方法就显得繁琐了。在这种情况下,我建议使用以下解决方案:

while whatever; do
    command || break
done

如果命令被中断并且有非零退出代码,循环将会退出。所以,除非command处理SIGINT,否则按下ctrl-C将停止当前命令并退出循环。
编辑:仔细阅读您的问题后,我发现您希望当前命令继续执行。在这种情况下,此解决方案不适用。

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