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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11203201/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 02:36:17  来源:igfitidea点击:

How to stop infinite loop in bash script gracefully?

bashshellinfinite-loop

提问by Samurai Girl

I need to run application in every X seconds, so, as far as cron does not work with seconds this way, I wrote a bash script with infinite loop having X seconds sleep in it.

我需要每 X 秒运行一次应用程序,因此,只要 cron 不能以这种方式使用秒,我编写了一个无限循环的 bash 脚本,其中有 X 秒的睡眠时间。

When I have to stop the running script manually, I would like to do it in a correct way - let the application complete functioning and just do not enter the loop for the next time.

当我必须手动停止正在运行的脚本时,我想以正确的方式执行此操作 - 让应用程序完成运行,并且下次不要进入循环。

Do you have any idea, how this can be achieved? I thought about passing arguments, but I could not find how to pass argument to running script.

你有什么想法,这是如何实现的?我想过传递参数,但我找不到如何将参数传递给正在运行的脚本。

回答by cdarke

You could trap a signal, say SIGUSR1:

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

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

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

Then, when you want to exit the loop at the next iteration:

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

kill -SIGUSR1 pid

Where pidis the process-id of the script. If the signal is raised during the sleep, it will wake (sleep sleeps until any signal occurs).

pid脚本的进程 ID在哪里。如果在睡眠期间发出信号,它将唤醒(睡眠睡眠直到出现任何信号)。

回答by kokosing

You may pass some arguments by a file. On each iteration you may read this file and see if your running condtions got changed.

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

回答by Fritz G. Mehner

The following structure may be appropriate if you have to do some cleanup anyway. Use kill as shown in cdarke's answer.

如果您无论如何都必须进行一些清理,则以下结构可能是合适的。如 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 '
while whatever; do
    command || break
done
' / PID ${$}" while : ; do # infinite loop # . . . sleep 10 done # . . . #=============================================================== # STATISTICS / CLEANUP #=============================================================== cleanup

回答by amaurea

The trap solution posted earlier is good for large loops, but cumbersome for the common case where you are just looping over a single or a few commands. In this case I recommend the following solution:

之前发布的陷阱解决方案适用于大循环,但对于仅循环单个或几个命令的常见情况来说很麻烦。在这种情况下,我推荐以下解决方案:

##代码##

This will exit the loop if command has a non-zero exit code, which will happen if it is interrupted. So unless commandhandles SIGINT, pressing ctrl-C will both stop the current command and exit the loop.

如果命令具有非零退出代码,这将退出循环,如果它被中断就会发生。因此,除非commandhandles SIGINT,否则按 ctrl-C 将停止当前命令并退出循环。

Edit: After reading your question more closely, I see that you want the current command to continue executing. In that case this solution does not apply.

编辑:更仔细地阅读您的问题后,我发现您希望当前命令继续执行。在这种情况下,此解决方案不适用。