[shell script] 신호를 이용해 쉘 스크립트 다루기

HYEOB KIM·2022년 4월 27일
0

Shell

목록 보기
55/71

'신호'란?

리눅스는 시스템에서 실행되는 프로세스와 통신하기 위해 신호를 사용합니다.
프로세스를 중지, 시작, 종료하기 위해 이러한 신호를 사용합니다.

신호의 종류

신호설명
1SIGHUP프로세스를 끊음
2SIGINT프로세스 중지
3SIGQUIT프로세스 중단
9SIGKILL무조건 프로세스 종료
15SIGTERM가능하면 프로세스를 종료
17SIGSTOP무조건 프로세스를 중단(종료 X)
18SIGTSTP프로세스 중단 또는 일시 중지(종료 X)
19SIGCONT중단된 프로세스를 실행
  • 기본적으로, BASH 쉘은 SIGQUIT(3) 및 SIGTERM(15) 신호를 받았을 때는 이를 무시합니다.
  • SIGHUP(1) 신호를 받으면 BASH 쉘은 종료됩니다. 종료되기 전에 실행 중인 모든 프로세스에 SIGHU 신호를 전달합니다.
  • 쉘은 이러한 신호를 쉘 스크립트에도 전달해서 처리하도록 합니다. 다만, 쉘 스크립트의 기본 동작은 이러한 신호를 통제하지 않으므로 스크립트 동작에 악영향을 미칠 수 있습니다. 이러한 상황을 막기 위해 스크립트가 신호를 인식하고 스크립트가 신호의 결과에 대한 준비를 하기 위해 명령을 수행하도록 만들 수 있습니다.

신호 만들기

프로세스 중지시키기

[Ctrl] + [C]

SIGINT 신호(프로세스 중지)를 만들어냅니다.

$ sleep 100
^C
$

프로세스 일시 중지시키기

[Ctrl] + [Z]

SIGTSTP 신호(프로세스를 중단 또는 일시중지(종료 x))를 만들어냅니다.

프로세스를 중지시키는 것은 종료와는 다릅니다. 프로세스를 중지하면 프로그램을 메모리에 남겨두며 중단되었던 곳에서부터 동작을 재개시킬 수 있습니다.

$ sleep 100
^Z
[1]+  Stopped                 sleep 100

만약 종료시키려 한다면 중단된 프로세스가 존재한다는 메시지를 출력합니다.

$ exit
logout
There are stopped jobs.

ps 명령으로 중단된 작업을 볼 수 있습니다.

$ ps -l
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  583315  583279  0  80   0 -  2102 do_wai pts/0    00:00:00 bash
0 T  1000  583456  583315  0  80   0 -  1369 do_sig pts/0    00:00:00 sleep
0 R  1000  583485  583315  0  80   0 -  2202 -      pts/0    00:00:00 ps

프로세스 종료시키기

$ kill -9 <PID>

SIGKILL 신호(무조건 프로세스 종료)를 생성합니다.

$ kill -9 583456

$ ps -l
F S   UID     PID    PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  583315  583279  0  80   0 -  2102 do_wai pts/0    00:00:00 bash
0 R  1000  583553  583315  0  80   0 -  2202 -      pts/0    00:00:00 ps
[1]+  Killed                  sleep 100

신호 트랩

만약 스크립트가 실행되고 있는 와중에 특정 신호가 발생한다면, 이를 가로챌(트랩) 수 있습니다.

trap commands signals

예를 들어, trap "echo ' You can't stop this script!'" SIGINT를 명령하면 SIGINT 신호가 들어올 때 가로채서(트랩) 정의된 명령어를 실행하고, 스크립트에 영향이 없도록 합니다.

아래 스크립트는 SIGINT 신호가 들어왔을 때 트랩해서 스크립트 실행이 중단되지 않도록 합니다.

$ cat test1
#!/bin/bash
trap "echo ' You cannot stop this script'" SIGINT

count=1
while [ $count -le 10 ]
do
        echo "Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

$ ./test1
Line #1
Line #2
Line #3
Line #4
Line #5
^C You cannot stop this script
Line #6
Line #7
^C You cannot stop this script
Line #8
Line #9
Line #10

[Ctrl] + [C]를 눌러 SIGINT 신호를 발생시켰지만 trap이 가로채서 스크립트 실행에는 영향이 없는 모습을 볼 수 있습니다.

스크립트 종료 트랩하기

trap을 사용할 때 EXIT를 입력하면 스크립트가 종료될 때 트랩할 수 있습니다.

$ cat test1
#!/bin/bash
trap "echo 'script exit...'" EXIT

count=1
while [ $count -le 5 ]
do
        echo "Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

$ ./test1
Line #1
Line #2
Line #3
Line #4
Line #5
script exit...

같은 신호에 대한 트랩 수정

같은 신호에 대한 트랩에 대해서 수정할 수 있습니다.

수정하는 법은 간단합니다.
단순히 trap을 한 번 더 작성하면 됩니다.

$ cat test1
#!/bin/bash
trap "echo 'You cannot stop first loop!'" SIGINT

count=1
while [ $count -le 5 ]
do
        echo "Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

trap "echo 'You cannot stop second loop!!'" SIGINT

count=1
while [ $count -le 5 ]
do
        echo "2 - Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

$ ./test1
Line #1
Line #2
^CYou cannot stop first loop!
Line #3
Line #4
Line #5
2 - Line #1
2 - Line #2
2 - Line #3
^CYou cannot stop second loop!!
2 - Line #4
2 - Line #5

트랩 제거

기존의 트랩을 제거할 수도 있습니다.

trap -- <signal>의 형식으로 제거가 가능합니다.

$ cat test1
#!/bin/bash
trap "echo 'You cannot stop first loop!'" SIGINT

count=1
while [ $count -le 5 ]
do
        echo "Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

trap -- SIGINT

count=1
while [ $count -le 5 ]
do
        echo "2 - Line #$count"
        sleep 1
        count=$[ $count + 1 ]
done

$ ./test1
Line #1
Line #2
^CYou cannot stop first loop!
Line #3
Line #4
Line #5
2 - Line #1
2 - Line #2
^C

두 번째 루프에서는 SIGINT 신호가 제대로 동작하는 것을 확인할 수 있습니다.

profile
Devops Engineer

0개의 댓글