Featured image of post [Bash Shell] 23. ps - 프로세스 상태 확인

[Bash Shell] 23. ps - 프로세스 상태 확인

ps는 실행 중인 프로세스를 스냅샷으로 찍어 보여주는 명령어다. GNU 계열의 -ef/-l 문법과 BSD 계열의 aux 문법이 왜 갈라졌는지, 필드 선택·정렬·트리 출력을 실전 예제로 다루고 ps aux | grep의 흔한 함정도 정리한다.

이 장을 읽기 전에

직전 챕터인 22장: 인용(Quoting)까지가 Part 3(파이프라인과 입출력)이었다. 파일을 읽고(cat), 텍스트를 검색·가공하고(13장: grep 등), 명령을 파이프로 연결하는(19장: 파이프) 법을 다뤘다면, 이 장부터는 Part 4(프로세스와 작업 제어)가 시작된다. 지금까지는 “파일과 텍스트"가 대상이었다면, 이제부터는 지금 이 순간 메모리에 올라와 실행 중인 프로그램 자체를 들여다본다.

이 장이 전제하는 지식은 파이프(|)로 명령 출력을 다른 명령에 연결하는 법과, grep으로 텍스트를 검색하는 법 정도다. 별도의 셸 스크립팅 지식은 필요 없다. 난이도는 입문–중급이며, 출력 필드 커스터마이징과 정렬 옵션에서 약간의 실무 감각이 필요하다.

다루지 않는 것: ps는 명령을 실행한 그 순간의 스냅샷만 보여준다. 화면이 갱신되며 지속적으로 리소스를 관찰하는 실시간 모니터링은 24장: top에서 다룬다. 확인한 프로세스에 시그널을 보내 종료하거나 백그라운드/포그라운드로 전환하는 제어는 25장: kill, jobs에서 다룬다.

당신의 수준에 맞는 경로

수준읽을 부분핵심 목표
입문개요+정신 모델, 사용법·옵션 표의 기본 예시(1–3번)ps -ef 또는 ps aux로 현재 실행 중인 프로세스 목록을 확인하고, grep으로 원하는 프로세스를 찾을 수 있다
중급출력 필드 제어(-o), 정렬(--sort), 트리 출력(--forest)필요한 필드만 골라 출력하고 CPU·메모리 기준으로 정렬해 문제 프로세스를 찾아낼 수 있다
심화주의사항·함정, 흔한 오개념GNU/BSD 옵션 문법이 섞였을 때 무슨 일이 벌어지는지 이해하고, %CPU 값의 실제 의미를 정확히 해석할 수 있다

개요 + 정신 모델

ps(“process status”)는 커널이 관리하는 프로세스 테이블의 그 순간 상태를 한 장 찍어 보여주는 카메라에 가깝다. 리눅스에서 ps는 실제로 /proc 가상 파일시스템을 읽어 각 프로세스의 PID·상태·메모리·CPU 시간 같은 정보를 수집하는데, /proc은 커널이 실행 중인 프로세스마다 실시간으로 갱신하는 정보를 파일처럼 노출한 것이다. 따라서 ps를 두 번 연달아 실행하면 두 결과는 서로 다른 시점의 스냅샷이며, ps 자체는 화면을 갱신하거나 값을 추적하지 않는다 — 지속 관찰이 필요하면 다음 장의 top으로 넘어가야 한다.

옵션 문법을 외우기 전에 알아야 할 더 중요한 사실은, ps의 옵션 체계가 역사적으로 완전히 다른 두 갈래로 갈라졌다는 점이다. 하나는 유닉스 표준(POSIX/System V) 계열로 -e, -f, -l처럼 대시(-)가 붙은 옵션을 쓰고, -e는 모든 프로세스, -f는 전체(full) 포맷을 의미한다. 다른 하나는 BSD 계열로 aux처럼 대시 없이 옵션 문자를 붙여 쓰는데, a는 다른 사용자의 프로세스까지 포함한 전체 목록, u는 사용자 지향(user-oriented) 포맷, x는 제어 터미널이 없는 프로세스까지 포함한다는 뜻이다. 리눅스의 GNU ps(procps-ng)는 두 문법을 모두 지원하도록 절충됐지만, 이 절충 자체가 뒤에서 다룰 함정(-aux vs aux)의 원인이 된다.

사용법 · 옵션

기본 문법은 ps [옵션]이다. 옵션은 크게 “어떤 프로세스를 고를지"와 “어떤 필드를 어떻게 보여줄지"로 나뉘고, 각각 GNU(UNIX 표준) 계열과 BSD 계열 표기가 따로 존재한다.

전체 프로세스 나열

옵션계열설명
-A, -eGNU/UNIX모든 프로세스를 보여준다
-aGNU/UNIX세션 리더와 제어 터미널이 없는 프로세스를 제외한 나머지를 보여준다
-dGNU/UNIX세션 리더를 제외한 모든 프로세스를 보여준다
-N, --deselectGNU/UNIX지정한 조건을 만족하는 프로세스를 제외하고 나머지를 보여준다(선택 반전)
aBSD터미널에 연결된 모든 사용자의 프로세스를 보여준다
xBSD제어 터미널이 없는 프로세스까지 포함한다
TBSD현재 터미널에 연결된 모든 프로세스를 보여준다

가장 기본적인 조합은 전체 프로세스를 나열한 뒤 원하는 이름으로 걸러내는 것이다.

1
2
# GNU 계열: 전체 프로세스 중 nginx 관련 프로세스만 검색
ps -ef | grep nginx

특정 프로세스 선택

옵션계열설명
-C <명령어>GNU/UNIX지정한 명령어 이름과 일치하는 프로세스만 보여준다
-p, --pid <PID>GNU/UNIX지정한 PID의 프로세스만 보여준다
-u, --user <사용자>GNU/UNIX지정한 유효 사용자(EUID, 이름도 가능)의 프로세스만 보여준다
-U, --User <사용자>GNU/UNIX지정한 실제 사용자(RUID)의 프로세스만 보여준다
-g <세션/그룹>GNU/UNIX세션 리더 또는 그룹 이름으로 필터링한다
-t <TTY>GNU/UNIX지정한 터미널에 연결된 프로세스만 보여준다

특정 PID의 부모 프로세스와 실행 명령을 확인할 때는 필터링과 필드 지정을 함께 쓴다.

1
2
# PID 1234의 pid, ppid, 실행 명령만 출력
ps -o pid,ppid,cmd -p 1234

출력 필드 제어 (포맷)

옵션계열보여주는 필드
-fGNU/UNIXUID, PID, PPID, C, STIME, TTY, TIME, CMD (전체 명령행 포함)
-lGNU/UNIXF, S, UID, PID, PPID, C, PRI, NI, ADDR, SZ, WCHAN, TTY, TIME, CMD (상세 long 포맷)
-jGNU/UNIXPID, PGID, SID, TTY, TIME, CMD (작업 제어용 포맷)
-o <필드,...>GNU/UNIX사용자가 지정한 필드만 원하는 순서로 출력
uBSDUSER, PID, %CPU, %MEM, VSZ, RSS, TTY, STAT, START, TIME, COMMAND
auxBSDa+u+x 조합 — 시스템 전체 프로세스를 사용자 지향 포맷으로

-o는 필요한 필드만 골라 파이프라인에 넘기기 좋은 형태로 만들 수 있어 스크립트에서 특히 유용하다.

1
2
# CPU 사용량 기준 상위 10개 프로세스를 pid, 명령, %CPU, %MEM만 출력
ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -10

정렬 · 표시 방식 제어

옵션설명
--sort=[+|-]key지정한 필드 기준으로 정렬한다. +는 오름차순(기본값), -는 내림차순
-H, --forest프로세스를 부모–자식 계층(트리) 구조로 보여준다
-m프로세스에 속한 스레드까지 함께 보여준다
-w, --cols터미널 폭에 잘리지 않도록 출력 폭을 넓힌다(반복 지정 시 더 넓어짐)
c축약되지 않은 원래 명령어 이름을 보여준다

BSD 계열 문법에서는 정렬 대신 메모리 사용량 상위를 빠르게 훑을 때 --sort를 함께 섞어 쓸 수 있다.

1
2
# 메모리 사용량 기준 내림차순 정렬 후 상위 목록만 확인
ps aux --sort=-%mem | head

프로세스 간 부모–자식 관계(어떤 프로세스가 어떤 셸에서 파생됐는지)를 한눈에 보려면 트리 출력이 유용하다.

1
2
# 프로세스를 트리 구조로 출력해 부모-자식 관계 확인
ps -ef --forest

주의사항 · 함정

GNU/BSD 문법을 섞으면 경고가 뜬다. 리눅스의 GNU ps-ef(대시 있음, UNIX 표준)와 aux(대시 없음, BSD)를 둘 다 지원하지만, -aux처럼 대시를 붙인 채 BSD 옵션 문자열을 쓰면 ps가 이를 표준 UNIX 옵션 -a -u -x(사용자 이름 x를 지정하려는 것)로 해석하려다 충돌해 문법 경고를 출력한다. 즉 ps auxps -aux는 겉보기엔 비슷해 보여도 내부적으로 완전히 다른 파싱 경로를 타므로, BSD 스타일을 쓸 때는 반드시 대시 없이 aux로 써야 한다.

스냅샷이라 %CPU·%MEM은 순간값이다. ps는 호출된 그 시점의 값만 보여주므로, 짧은 간격으로 급증하는 프로세스를 ps로 여러 번 반복 실행해 관찰하는 것은 비효율적이고 부정확하다. 지속적인 리소스 추이를 보려면 24장: top처럼 주기적으로 자동 갱신되는 도구를 써야 한다.

ps aux | grep은 grep 자기 자신도 매칭한다. ps aux | grep nginx를 실행하면 결과에 grep nginx라는 명령 자체도 하나의 프로세스로 잡혀 나온다. 흔한 회피법은 정규식 대괄호로 검색어 첫 글자를 감싸는 것(grep '[n]ginx', 이렇게 하면 grep 프로세스의 명령행 자체는 [n]ginx 패턴과 글자 그대로 일치하지 않는다)과 grep -v grep으로 결과에서 grep 프로세스를 제외하는 것이다. 더 근본적인 대안은 애초에 이런 문제가 없는 pgrep을 쓰는 것이다.

1
2
3
4
5
# 방법 1: 대괄호 트릭으로 grep 자신을 매칭에서 제외
ps aux | grep '[n]ginx'

# 방법 2: pgrep으로 애초에 grep을 거치지 않고 검색 (자기 자신을 매칭하지 않음)
pgrep -af nginx

흔한 오개념

%CPU는 “지금 이 순간의 사용률"이 아니다. 초심자가 가장 자주 오해하는 부분으로, ps%CPU 필드는 프로세스가 살아있는 동안 누적한 CPU 시간을 경과 시간으로 나눈 평균값이다. 방금 막 CPU를 많이 쓴 프로세스라도 오래 실행돼 온 프로세스라면 최근 순간의 부하가 희석되어 낮게 보일 수 있다. 진짜 “지금 이 순간"의 사용률이 필요하면 주기적으로 갱신되는 top의 값을 봐야 한다.

상태 코드 S(sleeping)가 “멈춰서 문제가 생겼다"는 뜻은 아니다. ps의 STAT 필드에서 S는 대개 인터럽트 가능한 대기(interruptible sleep) 상태로, 입출력이나 이벤트를 기다리며 정상적으로 실행을 잠시 양보한 상태다. 실제로 응답이 멎은 좀비/고아 프로세스를 의심할 때는 S 자체가 아니라 Z(좀비) 상태나 비정상적으로 긴 실행 시간을 함께 봐야 한다.

다음 장에서는

24장: top에서는 ps가 찍은 한 장의 스냅샷을 넘어, 화면이 주기적으로 갱신되며 CPU·메모리 사용량 상위 프로세스를 실시간으로 보여주는 도구를 다룬다.

평가 기준

  • GNU 계열(-ef, -l)과 BSD 계열(aux) 옵션 문법의 차이와 그 유래를 설명할 수 있다.
  • 목적에 맞게 -o로 출력 필드를 지정하고 --sort로 정렬할 수 있다.
  • ps aux | grep에서 grep 자신이 결과에 잡히는 문제를 진단하고 grep -v grep 또는 pgrep으로 회피할 수 있다.
  • %CPU 값이 순간 사용률이 아니라 프로세스 생존 기간 평균이라는 점을 설명할 수 있다.
  • ps가 스냅샷 도구라는 한계를 이해하고, 지속 모니터링이 필요할 때 top으로 전환할 판단을 할 수 있다.

참고