trap 으로 시그널 제어하기 - Ctrl + C 를 눌렀을 때 특정 처리를 수행하고 종료시키기

어떤 프로세스를 강제로 종료시키기 위해서는 일반적으로 Ctrl + C 를 이용하는데, 이는 프로세스에 SIGINT 시그널을 전달하는 것이다.

SIGINT 를 받은 프로세스는 일반적으로 그대로 종료되지만, 쉘스크립트에서는 trap을 사용해 이에 대한 처리가 가능하다.

trap 은 따옴표 안에 사용자가 수행할 명령어들을 넣고, 마지막에 특정 시그널명을 넣어줌으로써 해당 시그널을 제어할 수 있다.

trap ' ~ ' INT처럼 사용하며, 이는 INT 시그널에 대한 처리가 되는 것이다.

아래 예제는 무한 루프를 돌며 cnt 값을 증가시키는 간단한 프로그램인데, 사용자 인터럽트 발생 시 해당 값을 출력하고 프로그램을 exit 으로 종료시킨다.

#!/bin/bash

cnt=0
trap '
    echo
    echo $cnt
    exit
' INT

while :
do
    cnt=$(( $cnt + 1 ))
    echo $cnt
    sleep 1
done


만약 trap '' INT처럼 따옴표 안에 아무것도 실행시키지 않을 경우, SIGINT가 발생하더라도 아무 일도 일어나지 않는다.

즉 trap 으로 특정 시그널에 대한 제어를 수행하긴 하는데, 아무것도 수행하지 않는 것이기 때문에 프로세스가 실질적으로는 Ctrl+C 를 무시하는 것이 된다.

아래처럼 아무리 ^C 를 입력해도 반응이 없음을 확인할 수 있다.

$ bash test.sh
1
2
^C^C^C3
^C^C^C^C^C4
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C5
6
7
Killed

이렇게 exit 처럼 프로세스를 종료시키는 처리가 없을 경우에는, 다른 터미널에서 pid 를 확인한 뒤 강제적으로 죽여야 한다.

$ ps aux | grep test.sh
$ sudo kill -9 [PID]

또한 trap은 시그널을 캐치하는 것이기 때문에, nohup & 등으로 프로세스가 백그라운드에서 돌며 터미널을 종료해도 HUB 시그널이 전달되지 않을 경우는 trap 이 잡지 않는다.