如何通过发送 ctrl-z 之类的内容使循环 shell 脚本在循环后暂停,然后继续运行?

如何通过发送 ctrl-z 之类的内容使循环 shell 脚本在循环后暂停,然后继续运行?

我有一个循环文件​​的 shell 脚本。处理每个文件可能需要几个小时(受 CPU/GPU 限制)。有时我想在循环结束时暂停执行,当文件处理完成时,然后能够稍后恢复,类似于使用 ctrl-z 和 then 暂停的方式fg,但我希望它完成在实际暂停/进入后台之前当前循环。

基本上,我希望脚本在收到 ctrl-z (或类似的)时,等到它到达某一行后再停止。你如何实现这一目标?

答案1

我会用类似的东西:

#!/bin/bash
function catch_sig ()
{
    interrupted=1
    trap catch_sig SIGUSR1
}

interrupted=0

trap catch_sig SIGUSR1
echo "kill -s SIGUSR1 $$ to pause" 
  
while [[ there is more to do ]] ; do
   long_running_task
   if [[ 1 -eq "$interrupted" ]] ; then
        interrupted=0
        read -p "You rang? " junk
    fi
done 

然后,在另一个终端中执行kill -s SIGUSR1它告诉你的 PID。

请阅读man stty以查看是否有您想要使用的信号。读man signal kill pkill bash

答案2

解决方案

基本上,我希望脚本在收到 ctrl-z (或类似的)时,等到它到达某一行后再停止。

如果我是你,我会让特定行检查特定文件是否存在。如果文件存在,则脚本应向自身发送 SIGSTOP。

[ -e /path/to/file ] && kill -s STOP "$$"

我使用文件而不是信号的原因是你不能(或者至少不能轻易)撤销信号。对于文件来说,这很简单;如果您改变主意,只需删除该文件,脚本就不会自行停止。

脚本自行停止后,向其发送 SIGCONT,它将继续。在实践中,您很可能会从启用作业控制的交互式 shell 运行脚本;在这种情况下,shell 将检测脚本何时停止,您将能够随意fg运行bg脚本。

脚本是否尝试自动删除文件或允许文件保留并在下一次迭代中导致 SIGSTOP 取决于您,直到删除该文件。

Notekill -s STOP "$$"不等于Ctrl+ z。击键会导致终端(除非配置不同)将 SIGTSTP(而不是 SIGSTOP)发送到整个前台进程组。如果您确定解释脚本的 shell 是其进程组的领导者,那么您可能需要kill -s TSTP -- "-$$".如果您的脚本启动也在进程组中的异步进程并且您也想停止它们,则向该组发送信号将会产生影响。当进程收到 SIGSTOP(不能被捕获、阻止或忽略)或 SIGTSTP(可以)时,它们的行为可能会有所不同。kill …根据您的需要调整命令。


概念证明

以下脚本是否会自行停止,具体取决于 是否存在/tmp/blocker,但它只会在循环迭代结束时执行此操作for,而不是在中间执行。

#!/bin/sh -
for i in 1 2 3 4 5; do
   echo "processing $i"
   sleep 5
   echo "still processing"
   sleep 5
   echo "and processing some more"
   sleep 5
   echo "done processing $i"
   [ -e /tmp/blocker ] && kill -s STOP "$$"
done

相关内容