서비스 · 프로세스 관리 06 / 50 · Part 1. 프로세스 기초
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (systemd로 부팅한 Docker 격리 컨테이너, 테스트 계정 analyst)

1. 들어가며

ps는 가장 많이 쓰는 프로세스 명령어지만, 옵션 문법이 세 가지(BSD·UNIX·GNU)나 섞여 있어 "외워서 쓰는" 경우가 많다. ps aux와 ps -ef는 무엇이 다른지, 긴 명령어가 왜 잘리는지, 원하는 열만 뽑아 정렬하려면 어떻게 하는지를 정리해 두면 관제·점검 스크립트를 훨씬 정확하게 만들 수 있다.

이번 글에서는 ps 옵션을 선택(어떤 프로세스) → 출력(어떤 열) → 정렬 의 구조로 나누어 정리하고, 관제에서 바로 쓰는 템플릿을 만든다.

「리눅스 시스템 기초 32편」에서 ps의 기본 사용법을 다뤘다. 이번 글은 옵션 체계와 -o 활용에 집중한다.


2. 핵심 개념

2-1. 세 가지 문법

스타일형태대표 예특징
BSD대시 없음ps aux%CPU·%MEM·RSS 중심, 자원 확인에 편하다
UNIX(System V)대시 하나ps -efPPID가 보여 부모 추적에 편하다
GNU long대시 둘--sort, --forest, --ppid정렬·트리·세부 선택

ps aux의 a, u, x와 ps -aux는 다른 뜻 이다. 대시를 붙이면 UNIX 문법으로 해석되어 "사용자 x의 프로세스"를 찾으려 하기 때문에 경고가 날 수 있다. BSD 옵션에는 대시를 붙이지 않는다.

2-2. 자주 쓰는 선택 옵션

옵션의미
-e / ax모든 프로세스
-p 1,31특정 PID
-u analyst특정 사용자(effective UID)
-C sshd,crond실행 파일 이름(comm)으로 선택
--ppid 356특정 부모의 자식
-t pts/0특정 터미널

2-3. 관제에 유용한 출력 열 (-o)

열의미왜 필요한가
pid,ppid자신과 부모실행 주체 추적
user / uid실행 계정권한 판단
lstart정확한 시작 시각로그와 시간 상관 분석
etimes실행 후 경과 초"최근 1시간 안에 시작된 프로세스" 필터
stat상태04편
%cpu,%mem,rss자원 사용량마이너·메모리 누수
comm짧은 이름(15자)이름 기반 선택
args / cmd전체 명령 인자실행 내용 확인
nlwp스레드 수멀티스레드 여부

3. 동작 원리

ps 옵션 체계 한눈에 보기

ps는 /proc/[0-9]*를 모두 읽고(05편) 선택 조건으로 거른 뒤, 요청한 열만 표로 만든다.

/proc/1, /proc/21, /proc/31 ...  (모든 PID 디렉터리)
   ↓ 선택: -e / -u / -p / -C / --ppid
   ↓ 출력: -o 열 목록 → /proc/PID/stat, status, cmdline 에서 값 추출
   ↓ 정렬: --sort=-rss
화면 출력 (터미널 폭에 맞춰 마지막 열을 자름)

마지막 줄이 중요하다. ps는 터미널 폭에 맞춰 명령어 열을 자른다. 파이프로 다른 명령에 넘길 때도 폭 제한이 걸릴 수 있으므로, 전체 인자가 필요하면 -ww를 붙인다.


4. 명령어 실습

# 1) BSD vs UNIX 스타일
ps aux | head -6
ps -ef | head -6

# 2) 필요한 열만 + 정렬 (메모리 많이 쓰는 순)
ps -eo pid,ppid,user,%cpu,%mem,rss,etimes,stat,comm --sort=-rss | head -8

# 3) 정확한 시작 시각과 경과 시간
ps -o pid,user,lstart,etime,cmd -p 1,$(pgrep -xo sshd)

# 4) 이름·사용자로 선택
ps -C sshd,sshd-session -o pid,ppid,user,args
ps -u analyst -o pid,tty,stat,cmd

# 5) 사용자별 프로세스 수 집계
ps axo user= | sort | uniq -c | sort -rn

# 6) (Ubuntu) 긴 인자와 스레드
ps -o pid,nlwp,stat,cmd -p $P        # 잘린 출력
ps -ww -o pid,cmd -p $P              # 전체 출력
ps -L -o pid,lwp,nlwp,stat,comm -p $P  # 스레드별

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · analyst@rocky9-lab — BSD 스타일(aux)과 UNIX 스타일(-ef)

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — -o 로 필요한 열만, --sort 로 정렬

실제 실행 결과 — Ubuntu 24.04.5 · root@ubuntu-lab — 잘린 명령어 보기 (-ww) 와 스레드 (-L)

텍스트 원본(실제 출력):

[analyst@rocky9-lab ~]$ ps aux | head -6
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.3  0.1  24388 13964 ?        Ss   11:48   0:00 /usr/sbin/init
root          21  0.0  0.1  28512 11128 ?        Ss   11:48   0:00 /usr/lib/systemd/systemd-journald
root          31  0.0  0.0  11788  7940 ?        Ss   11:48   0:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-
root          32  0.0  0.1  20904  9728 ?        Ss   11:48   0:00 /usr/lib/systemd/systemd-logind
root          37  0.0  0.0   4728  2708 ?        Ss   11:48   0:00 /usr/sbin/atd -f
[analyst@rocky9-lab ~]$ ps -ef | head -6
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 11:48 ?        00:00:00 /usr/sbin/init
root          21       1  0 11:48 ?        00:00:00 /usr/lib/systemd/systemd-journald
root          31       1  0 11:48 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root          32       1  0 11:48 ?        00:00:00 /usr/lib/systemd/systemd-logind
root          37       1  0 11:48 ?        00:00:00 /usr/sbin/atd -f
[analyst@rocky9-lab ~]$ ps aux | wc -l; ps -ef | wc -l
17
17
[root@rocky9-lab ~]# ps -eo pid,ppid,user,%cpu,%mem,rss,etimes,stat,comm --sort=-rss | head -8
    PID    PPID USER     %CPU %MEM   RSS ELAPSED STAT COMMAND
      1       0 root      0.3  0.1 13964      73 Ss   systemd
    437       1 root      0.0  0.1 11964       0 Ss   systemd
    385       1 analyst   2.0  0.1 11932       1 Ss   systemd
    433      31 root      1.0  0.1 11528       1 Ss   sshd-session
     21       1 root      0.0  0.1 11156      67 Ss   systemd-journal
     32       1 root      0.0  0.1  9728      65 Ss   systemd-logind
     31       1 root      0.0  0.0  7940      65 Ss   sshd
[root@rocky9-lab ~]# ps -o pid,user,lstart,etime,cmd -p 1,$(pgrep -xo sshd)
    PID USER                      STARTED     ELAPSED CMD
      1 root     Thu Sep 24 11:48:18 2026       01:13 /usr/sbin/init
     31 root     Thu Sep 24 11:48:26 2026       01:05 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
[root@rocky9-lab ~]# ps -C sshd,sshd-session -o pid,ppid,user,args
    PID    PPID USER     COMMAND
     31       1 root     sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
    433      31 root     sshd-session: root [priv]
    446     433 root     sshd-session: root@pts/0
[root@rocky9-lab ~]# ps -u analyst -o pid,tty,stat,cmd
    PID TT       STAT CMD
    385 ?        Ss   /usr/lib/systemd/systemd --user
    387 ?        S    (sd-pam)
[root@rocky9-lab ~]# ps axo user= | sort | uniq -c | sort -rn
     16 root
      2 dbus
      2 analyst
root@ubuntu-lab:~# python3 -c 'import threading,time; [threading.Thread(target=time.sleep,args=(60,),daemon=True).start() for _ in range(3)]; time.sleep(60)' --very-long-argument-for-width-test=/opt/app/config/production/settings.yaml &
root@ubuntu-lab:~# sleep 1.5; P=$!
root@ubuntu-lab:~# ps -o pid,nlwp,stat,cmd -p $P
    PID NLWP STAT CMD
    378    4 Sl+  python3 -c import threading,time; [threading.Thread(target=time.sleep,args=(60,),daemon=True
root@ubuntu-lab:~# ps -ww -o pid,cmd -p $P
    PID CMD
    378 python3 -c import threading,time; [threading.Thread(target=time.sleep,args=(60,),daemon=True).start() for _ in range(3)]; time.sleep(60) --very-long-argument-for-width-test=/opt/app/config/production/settings.yaml
root@ubuntu-lab:~# ps -L -o pid,lwp,nlwp,stat,comm -p $P
    PID     LWP NLWP STAT COMMAND
    378     378    4 Sl+  python3
    378     380    4 Sl+  python3
    378     381    4 Sl+  python3
    378     382    4 Sl+  python3
root@ubuntu-lab:~# ps -eo pid,stat,cmd --no-headers | awk '$2 ~ /l/' | head -3
    378 Sl+  python3 -c import threading,time; [threading.Thread(target=time.sleep,args=(60,),daemon=True).sta
root@ubuntu-lab:~# kill $P

6. 결과 해석

관찰의미
ps aux 헤더: %CPU %MEM VSZ RSS ... START자원 중심 형식. VSZ는 가상 메모리, RSS는 실제 물리 메모리(KB)
ps -ef 헤더: UID PID PPID C STIME부모 PID가 바로 보인다. 트리 분석은 -ef가 편하다
두 결과 모두 18줄형식만 다르고 대상은 같다 (헤더 포함 17개 프로세스)
--sort=-rss 결과 1위가 systemd-는 내림차순. 메모리 순위를 바로 확인할 수 있다
ELAPSED 0 인 sshd-session·systemd지금 막 로그인해서 생긴 프로세스다. etimes로 "최근에 생긴 것"을 골라낼 수 있다
lstart = Thu Sep 24 11:48:26 2026초 단위 정확한 시각. START(시:분) 열보다 로그 대조에 적합하다
ps -C sshd,sshd-session콤마로 여러 이름을 한 번에 선택했다. listener → [priv] → root@pts/0 구조가 보인다
uniq -c 결과 root 16, dbus 2, analyst 2계정별 프로세스 수. 평소 기준선과 비교하면 이상 계정 활동을 찾을 수 있다
Ubuntu 기본 출력에서 인자 뒤가 잘림터미널 폭(110열) 때문. -ww에서 --very-long-argument...settings.yaml까지 전부 보였다
NLWP 4, ps -L에서 LWP 4개메인 스레드 1 + 생성한 스레드 3. 모두 같은 PID(378)를 공유한다
STAT Sl+l = 멀티스레드. 04편의 보조 플래그

7. 보안 관점

주제내용
잘린 명령어공격 명령은 길다(base64 페이로드, 긴 URL). -ww 없이 보면 핵심 부분이 잘려 판단을 놓친다
args vs commargs는 프로세스가 스스로 바꿀 수 있다(exec -a, prctl). comm도 바꿀 수 있다. 최종 판단은 /proc/PID/exe로 한다 (43편)
계정별 집계평소 프로세스가 없던 서비스 계정(www-data, nginx)의 프로세스 수가 늘면 조사 대상이다
시간 기준etimes로 "최근 N초 안에 시작된 프로세스"를 뽑으면 침해 직후 생긴 프로세스를 빠르게 좁힐 수 있다

8. 보안관제 관점

[Detection]  침해 의심 서버 — "지금 무엇이 돌고 있나?"를 한 번에 저장
     ↓
[수집]       ps -eo pid,ppid,user,lstart,etimes,stat,%cpu,%mem,args -ww --sort=-%cpu > ps_$(date +%F_%H%M).txt
     ↓
[좁히기]     ps -eo pid,etimes,user,args -ww | awk '$2 < 3600'          # 최근 1시간
             ps -eo user= | sort | uniq -c | sort -rn                    # 계정별 수
             ps -eo pid,user,%cpu,args --sort=-%cpu | head               # CPU 상위
     ↓
[판단]       기준선(baseline)과 비교 → 새 계정·새 프로세스·비정상 경로
     ↓
[Response]   의심 PID 로 /proc 증거 수집(05편) → 조치
관점내용
증거 보존ps 결과는 시각이 들어간 파일로 저장한다. 조치 전후를 비교할 수 있다
baseline정상 상태의 ps -eo user,comm 목록을 평소에 저장해 두면 차이 비교가 쉽다
스크립트사람이 읽을 때는 aux, 스크립트는 -eo ... --no-headers로 파싱하기 쉬운 형식을 쓴다

9. 실무에서 자주 발생하는 실수

실수결과예방
ps -aux (대시 + BSD 옵션)경고 또는 의도와 다른 선택BSD 옵션은 대시 없이 ps aux
ps aux \| grep nginxgrep 자신이 결과에 섞인다pgrep -a nginx 또는 ps -C nginx
명령어가 잘린 결과로 판단악성 인자를 놓침-ww 또는 /proc/PID/cmdline
START 열로 시간 대조하루 지난 프로세스는 날짜만 보인다lstart 사용
%CPU를 순간값으로 이해ps의 %CPU는 수명 전체 평균 이다순간 사용률은 top(07편)

10. 실습 체크리스트

[ ] ps aux 와 ps -ef 의 열 차이를 설명할 수 있다
[ ] -o 로 pid,ppid,user,lstart,etimes,args 를 출력했다
[ ] --sort=-rss 로 메모리 상위 프로세스를 정렬했다
[ ] -C, -u, -p, --ppid 로 대상을 선택했다
[ ] -ww 로 잘리지 않은 전체 인자를 확인했다
[ ] -L / nlwp 로 스레드를 확인했다

11. 핵심 정리

  • ps는 BSD(aux)·UNIX(-ef)·GNU(--sort) 문법을 모두 받는다. BSD 옵션에는 대시를 붙이지 않는다.
  • 옵션은 선택(-e, -u, -p, -C) → 출력(-o) → 정렬(--sort) 로 나누어 조합한다.
  • 관제에서는 lstart(정확한 시각), etimes(경과 초), args -ww(전체 인자)가 특히 중요하다.
  • ps의 %CPU는 평균값이다. 순간 부하는 top으로 본다.
  • 결과는 시각이 포함된 파일로 저장해 기준선과 비교한다.

12. 다음 편 예고

다음 글 「07. top으로 실시간 자원 모니터링」 에서는 top의 요약 영역(load average, %Cpu, Mem)을 해석하고, 배치 모드(-b) 로 결과를 파일에 남기는 방법, 정렬·사용자 필터·스레드 보기를 실습한다.


참고 자료


시리즈 이동

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글