프로세스 종료 (kill, killall)
스크립트를 작성하다 보면 특정 프로세스를 찾아서 종료해야 할 때가 생깁니다. 응답하지 않는 서버 프로세스를 재시작하거나, 이전에 실행한 스크립트가 아직 살아있는지 확인하고 중복 실행을 막거나, 모든 백그라운드 작업을 일괄 종료하는 경우입니다.
리눅스에서 프로세스를 종료하는 핵심은 시그널입니다. 단순히 "꺼라"가 아니라 어떤 방식으로 종료할지 선택할 수 있습니다.
시그널 개요
시그널은 프로세스에 보내는 비동기 알림입니다. 프로세스는 시그널을 받으면 기본 동작을 수행하거나, trap으로 등록한 핸들러를 실행하거나, 시그널을 무시할 수 있습니다. 시그널 전체 목록은 kill -l로 확인합니다.
kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
...
프로세스 종료에 주로 사용하는 시그널을 정리하면 다음과 같습니다.
| 시그널 | 번호 | 의미 | 기본 동작 | 처리 가능 |
|---|---|---|---|---|
| SIGHUP | 1 | 터미널 종료 | 종료 | 가능 |
| SIGINT | 2 | Ctrl+C | 종료 | 가능 |
| SIGTERM | 15 | 정상 종료 요청 | 종료 | 가능 |
| SIGKILL | 9 | 강제 종료 | 즉시 종료 | 불가능 |
| SIGSTOP | 19 | 일시 정지 | 정지 | 불가능 |
| SIGCONT | 18 | 재개 | 재개 | 가능 |
kill 명령어
kill은 프로세스에 시그널을 보내는 명령어입니다. 이름과 달리 반드시 프로세스를 죽이는 것이 아니라 시그널을 전달하는 것입니다.
# 기본: SIGTERM(15)을 보냄 (정상 종료 요청)kill 12345# 시그널 번호 지정kill -9 12345 # SIGKILL (강제 종료)kill -15 12345 # SIGTERM (정상 종료)kill -1 12345 # SIGHUP# 시그널 이름으로 지정kill -SIGTERM 12345kill -TERM 12345# 현재 쉘 자신에게 시그널 보내기kill -TERM $$
SIGTERM vs SIGKILL
이 두 시그널의 차이를 이해하는 것이 중요합니다.
SIGTERM(15)은 "정상적으로 종료해 달라"는 요청입니다. 프로세스가 이 시그널을 받으면 현재 작업을 마무리하고, 열린 파일을 닫고, 임시 파일을 정리한 뒤 종료할 기회를 갖습니다. 대부분의 잘 만들어진 서버 프로그램은 SIGTERM을 받으면 graceful shutdown을 수행합니다. 프로세스가 SIGTERM을 무시하거나 trap으로 처리하도록 설정했다면 종료되지 않을 수 있습니다.
SIGKILL(9)은 즉시 강제 종료입니다. 커널이 직접 프로세스를 제거하기 때문에 프로세스가 가로챌 수 없습니다. 어떤 상황에서도 반드시 종료됩니다. 하지만 뒷정리 기회가 없으므로 임시 파일이 남거나, 데이터베이스 트랜잭션이 불완전하게 종료될 위험이 있습니다.
# 올바른 순서: SIGTERM 먼저, 안 되면 SIGKILLkill -TERM 12345sleep 5if kill -0 12345 2>/dev/null; then echo "SIGTERM 후에도 살아있음. 강제 종료." kill -KILL 12345fi
kill -0 PID는 실제 시그널을 보내지 않고 프로세스가 살아있는지만 확인합니다. 에러가 나지 않으면 프로세스가 존재하는 것입니다.
killall: 이름으로 프로세스 종료
PID를 모를 때 프로세스 이름으로 종료합니다.
# nginx 프로세스 모두 종료 (SIGTERM)killall nginx# SIGKILL로 강제 종료killall -9 nginxkillall -KILL nginx# 특정 사용자의 프로세스만 종료killall -u student python3# 대화형 확인 (-i)killall -i python3# 종료 전 확인만 (-e: 정확한 이름 매칭)killall -e python3.12
killall은 정확한 이름 매칭을 합니다. killall python이라고 하면 python3는 종료되지 않습니다. -e 없이 실행하면 이름으로 시작하는 모든 프로세스를 종료하므로 주의해야 합니다.
pkill: 패턴으로 프로세스 종료
pkill은 정규표현식 패턴으로 프로세스를 찾아 종료합니다. killall보다 유연합니다.
# python으로 시작하는 모든 프로세스 종료pkill python# 정규표현식 사용pkill -f "python.*script.py"# 특정 사용자의 프로세스pkill -u student python# 시그널 지정pkill -TERM -f "myapp"# 현재 터미널의 프로세스만pkill -t pts/0 python
-f 옵션은 프로세스 이름뿐 아니라 전체 명령줄을 패턴으로 검색합니다. python /home/student/jobs/process.py처럼 전체 경로를 포함한 명령을 찾을 때 유용합니다.
pgrep: 프로세스 검색
pgrep은 pkill과 같은 방식으로 검색하지만 종료하지 않고 PID만 출력합니다. 프로세스가 실행 중인지 확인하거나 PID를 구해야 할 때 사용합니다.
# nginx의 PID 출력pgrep nginx# 프로세스 이름과 함께 출력pgrep -l nginx# 전체 명령줄로 검색pgrep -f "python.*monitor"# 특정 사용자의 프로세스pgrep -u student python# 프로세스 존재 여부 확인 (종료 코드만)if pgrep nginx > /dev/null 2>&1; then echo "nginx가 실행 중입니다."else echo "nginx가 실행되지 않고 있습니다."fi
실습: 특정 프로세스를 찾아서 종료하는 스크립트
프로세스 이름을 받아 안전하게 종료하는 함수를 만들고, 실용적인 관리 스크립트에 활용합니다.
#!/usr/bin/env bash# 파일: safe_kill.shset -euo pipefail# 사용법 출력usage() { echo "사용법: $0 <프로세스이름> [SIGTERM_대기시간(초)]" echo "예시: $0 myapp 10" exit 1}# 안전한 프로세스 종료 함수safe_kill() { local process_name="$1" local wait_seconds="${2:-10}" # 프로세스 존재 확인 if ! pgrep -f "$process_name" > /dev/null 2>&1; then echo "'$process_name' 프로세스가 실행 중이지 않습니다." return 0 fi # 실행 중인 PID 목록 local pids pids=$(pgrep -f "$process_name" | tr '\n' ' ') echo "종료 대상 PID: $pids" # SIGTERM으로 정상 종료 시도 echo "SIGTERM 전송..." pkill -TERM -f "$process_name" || true # 대기 local elapsed=0 while pgrep -f "$process_name" > /dev/null 2>&1; do if (( elapsed >= wait_seconds )); then echo "${wait_seconds}초 경과. SIGKILL로 강제 종료..." pkill -KILL -f "$process_name" || true sleep 1 break fi echo -n "." sleep 1 elapsed=$((elapsed + 1)) done echo "" # 최종 확인 if pgrep -f "$process_name" > /dev/null 2>&1; then echo "경고: 프로세스가 여전히 실행 중입니다." return 1 else echo "'$process_name' 종료 완료." return 0 fi}# 인수 확인[[ $# -lt 1 ]] && usagesafe_kill "$1" "${2:-10}"
다음처럼 사용합니다.
chmod +x safe_kill.sh# 기본 10초 대기./safe_kill.sh myapp# 5초 대기./safe_kill.sh "python.*worker" 5
실행 결과입니다.
종료 대상 PID: 12345 12346
SIGTERM 전송...
......
'myapp' 종료 완료.
SIGTERM으로 정상 종료를 시도하고, 일정 시간이 지나도 살아있으면 SIGKILL로 강제 종료하는 이 패턴은 실무에서 프로세스 관리 스크립트를 작성할 때 표준적으로 사용됩니다.