ctrl-z와 같은 명령을 보내 루프 이후에 루프 쉘 스크립트를 일시 중지한 다음 계속 실행하려면 어떻게 해야 합니까?

ctrl-z와 같은 명령을 보내 루프 이후에 루프 쉘 스크립트를 일시 중지한 다음 계속 실행하려면 어떻게 해야 합니까?

파일을 반복하는 쉘 스크립트가 있습니다. 각 파일을 처리하는 데 몇 시간이 걸릴 수 있습니다(CPU/GPU 제한). 때로는 파일 처리가 완료되면 루프 끝에서 실행을 일시 중지하고 나중에 다시 시작할 수 있기를 원합니다. Ctrl-z를 누른 다음 을 사용하여 일시 중지하는 방법과 유사 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를 보내면 계속됩니다. 실제로는 작업 제어가 활성화된 대화형 셸에서 스크립트를 실행할 가능성이 높습니다. 이 경우 셸은 스크립트가 중지되는 시기를 감지하고 사용자가 원하는 대로 스크립트를 fg실행할 수 있습니다 .bg

스크립트가 자동으로 파일을 삭제하려고 시도할지 아니면 파일을 그대로 두고 다음 반복에서 SIGSTOP을 발생시킬지 여부는 사용자에게 달려 있습니다.파일을 삭제합니다.

참고 는 + kill -s STOP "$$"와 같지 않습니다 . 키 입력을 통해 터미널은 (다르게 구성되지 않는 한) 전체 포그라운드 프로세스 그룹에 SIGTSTP(SIGSTOP 대신)를 보냅니다. 스크립트를 해석하는 쉘이 해당 프로세스 그룹의 리더라고 확신하는 경우에는 다음을 수행할 수 있습니다 . 스크립트가 프로세스 그룹에 있는 비동기 프로세스를 시작하고 이를 중지하려는 경우 다음으로 신호를 보냅니다. 그 그룹은 효과를 가질 것입니다. 프로세스는 SIGSTOP(잡히거나 차단되거나 무시될 수 없음) 또는 SIGTSTP(할 수 있음)를 수신할 때 다르게 동작할 수 있습니다. 필요에 맞게 명령을 조정하십시오.Ctrlzkill -s TSTP -- "-$$"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

관련 정보