SIGINT가 함수 호출 및 하위 프로세스를 중단하지 못하도록 방지

SIGINT가 함수 호출 및 하위 프로세스를 중단하지 못하도록 방지

다음 스크립트를 고려해보세요.

#!/bin/bash

set -o pipefail
set -o history

trapper() {
   func="$1" ; shift
   for sig ; do
      trap "$func $sig" "$sig"
   done
}

err_handler () {
  case $2 in
    INT)
       stop_received=1
    ;;
    TSTP)
    ;;
    ERR)
       if [[ $2 != "INT" ]]; then # for some reason, ERR gets triggered on SIGINT
          code=$?
          if [ $code -ne 0 ]; then
             echo "Failed on line $1"
             echo "$BASH_COMMAND returned $?"
             echo "Content of variables at the time of failure:"
             echo "$(set -o posix; set)"
             exit 1
          fi
       fi
    ;;
  esac
}

main() {
   ping -c 5 www.google.com # this is a test to see if INT interrupts main()
   # do a bunch of stuff, I mean a real bunch of stuff, like check some
   # files, do some processing, connect to a database,
   # do more processing, move some files around, you get the drift
}

exec > >(tee -a my.log)
exec 2>&1

trapper 'err_handler $LINENO' INT TSTP ERR
while main
do
  if [[ "$stop_received" == "1" ]]; then
     break
  fi
  setsid sleep 2 & wait
done
trap ERR

내가 달성하고 싶은 것은 main() 함수가 0이 아닌 값을 반환할 때까지, 즉 오류가 발생하거나 SIGINT가 수신될 때까지 무한 루프에서 스크립트를 실행하는 것입니다.

그러나 SIGINT가 main() 실행을 중지하는 것을 원하지 않습니다. 즉, 스크립트가 SIGINT를 수신하면 main()이 완료될 때까지 기다렸다가 정상적으로 종료해야 합니다. 그런데 Ctrl+C를 누르면 핑이 중단되는 것을 볼 수 있습니다. 현재 저는 이것이 작동하는지 확인하기 위해 main() 아래의 모든 항목을 주석 처리했습니다. 핑이 중단되었으므로 main() 아래의 다른 명령도 중단될 것이라고 가정합니다. 핑이 중단되면 처리가 $stop_received=1을 확인하는 줄로 점프한 다음 루프가 중단되고 스크립트가 종료됩니다. 인터럽트를 에코로 바꾸면 스크립트는 기본 while 루프의 다음 반복을 계속합니다.

SIGINT가 현재 실행 중인 명령을 중단하는 것을 방지하는 방법은 무엇입니까? 내 스크립트는 데이터베이스의 DML 문을 포함하여 많은 작업을 수행하므로 main()을 중단하면 많은 문제가 발생할 수 있습니다.

둘째, 스크립트는 Ctrl+Z도 캡처하지 않습니다. 또는 오히려 스크립트가 ctrl+z에 멈춰 종료하려면 pid를 종료해야 합니다. 나는 sleep이 스크립트 자체가 아니라 bash의 자식이라고 생각하며 ctrl+z는 스크립트를 일시 중지시켜 sleep을 가두게 됩니다. 그래서 setid를 설정하고 잠자기를 기다리지만 여전히 중단됩니다.

감사해요.

답변1

Ctrl+ 효과를 제거하는 방법에는 여러 가지가 있습니다 C.

  • 신호가 발생하지 않도록 터미널 설정을 변경하십시오.
  • 차단이 해제되면 나중에 전달하기 위해 신호를 저장하기 위해 신호를 차단합니다.
  • 신호를 무시하거나 이에 대한 핸들러를 설정하십시오.
  • 백그라운드 프로세스 그룹에서 하위 프로세스를 실행합니다.

Ctrl+가 C눌려졌음 을 감지하고 싶기 때문에 신호를 무시하는 것은 옵션이 아닙니다. 터미널 설정을 변경할 수 있지만 그런 다음 사용자 정의 키 입력 처리 코드를 작성해야 합니다. 쉘은 신호 차단에 대한 액세스를 제공하지 않습니다.

그러나 별도의 프로세스 그룹에서 하위 프로세스를 실행하면 하위 프로세스가 신호를 자동으로 수신하지 못하도록 격리할 수 있습니다. 기본적으로 대화형 셸은 별도의 프로세스 그룹에서 백그라운드 명령을 실행하지만 비대화형 셸은 동일한 프로세스 그룹에서 실행하며 포그라운드 프로세스 그룹의 모든 프로세스는 터미널 이벤트로부터 신호를 받습니다. 쉘에게 말해별도의 프로세스 그룹에서 백그라운드 작업을 실행하려면 다음을 실행하세요.set -m. 실행은 별도의 프로세스 그룹에서 강제로 실행하는 setsid ping …또 다른 방법 입니다.ping

set -m
interrupted=
trap 'echo Interrupted, but ping may still be running' INT
set -m
ping … &
while wait; [ $? -ge 128 ]; do echo "Waiting for background jobs"; done
echo ping has finished

Ctrl백그라운드 프로세스 그룹을 일시 중단 하려면 Z셸에서 신호를 전파해야 합니다.

쉘 스크립트에서는 세밀한 신호 제어가 다소 어렵고, ATT ksh 이외의 쉘에서는 특수한 경우가 발생할 때 문제가 발생하는 경향이 있으므로 Perl, Python 또는 Ruby와 같이 더 많은 제어를 제공하는 언어를 사용하는 것이 좋습니다.

답변2

인터럽트 루틴을 비활성화합니다:

트랩 "" ERR HUP INT QUIT TERM TSTP TTIN TTOU

그러나 하위 명령이 트랩 자체를 처리하고 명령이 실제로 완료되어야 하는 경우 신호가 전달되는 것을 방지해야 합니다.

추가 명령 설치에 신경 쓰지 않는 Linux 사용자의 경우 다음을 사용할 수 있습니다.

기다리다[주문하다]

또는 조정할 수 있습니다.최신 소스 코드를 기다려주세요필요에 따라 프로그램에 추가하거나 다음 코드를 사용하십시오.자일스의 대답. 단점은 업스트림 업데이트의 이점을 누릴 수 없다는 것입니다.

다른 터미널과 서비스 관리자는 여전히 "명령"을 종료할 수 있습니다. 서비스 관리자가 "명령"을 닫을 수 없도록 하려면 해당 명령을 적절한 종료 모드 및 종료 신호 세트를 사용하여 서비스로 실행해야 합니다.

관련 정보