ps - “A good process produces good results.”




ps reports a snapshot of the current processes. It accepts several kinds of options :
pgrep is sometimes more appropriate than ps [basic options] | grep


Unless explicitly specified, process selection options are additive, i.e. the flags below are logically OR'ed.
Flag Usage
-a select all processes except both session leaders and processes not associated with a terminal
  • select all processes with a terminal (tty) (by actually lifting the BSD-style "only yourself" restriction)
  • with x : select all processes
-A or -e select All processes
-C commandList select processes whose executable name is given in commandList
--cols n --columns n set screen width to n columns
f forest : ASCII-art process hierarchy
-f full-format listing
-F extended full-format listing. Implies -f
l display BSD long format
  • show threads
  • with -f, show columns :
    • LWP : thread ID
    • NLWP : number of threads
o formatSpecString
-o formatSpecString
--format formatSpecString
introduces the output format specifiers
-O formatSpecString
(uppercase "o")
same as -o but preloaded with some default columns. Identical to -o pid,format,state,tname,time,command
p pidlist
-p pidlist
--pid pidlist
select by PID
--ppid n select processes which parent process ID is n
-T display PID of Threads, aka SPID
u display user-oriented format
U userId
-u userId
--user userId
select processed owned by userId (user name orUID)
Z or -M add a column of security data (for SELinux)

ps may display the user's uid instead of the user's name if the username is longer than 7 characters.

Output column headers :

Some column headers are sometimes cryptic, and single-letter values are hard to find in the man. To get the full list :
  1. LANG=C man -P 'less -p "^STANDARD FORMAT SPECIFIERS"' ps
  2. scroll
Header Usage output by command Details
C CPU usage % ps -eF | head -10 integer value of the percent usage over the lifetime of the process
F process flags ps -l | head -10
  • 0 : no flag set
  • 1 : forked but didn't exec
  • 4 : used super-user privileges
S process state ps -l | head -10 values

Output format specifiers (source, or : LANG=C man -P 'less -p "^STANDARD FORMAT SPECIFIERS"' ps) :

Specifier Usage
args displays the command that is executing, with all its arguments
comm displays the name of the command that is executing (the binary ?)
etime elapsed time since the process was started : [[dd-]hh:]mm:ss
etimes elapsed time since the process was started, in seconds
gid EGID of the process. See uid
lstart date + time the process was started : Fri Aug 21 23:32:21 2015.
lwp ID of the light weight process (thread)
nlwp thcount number of light weight processes (threads)
pcpu %cpu ratio : cputime of the process / realtime
pid PID of the selected process
ppid PID of the parent of the selected process
pmem %mem ratio : RSS / physical memory
rss rssize rsz resident set size : the non-swapped physical memory that a task has used, in kiloBytes (details : 1, 2)
sgi_p ID of the processor currently executing the process. Will display * if the process is not currently being executed
start If the process was started less than 24 hours ago, display its start time in 24h:mm:ss format. Otherwise, display the start date formatted like Aug 21.
start_time If the process was started today, display its start time in 24h:mm format. Otherwise, display the start date formatted like Aug21.
state state of the process :
time cputime cumulative CPU time, [DD-]HH:MM:SS format
uid EUID of the process
ps -o comm,user,uid,gid
user euser uname name of the user owning the process
vsize vsz virtual memory (=SWAP) size of the specified process, in KiB (needs details)
The output format can be specified in the form :
ps -o comma-separated,list,of,specifiers
You can change a column header by specifying a custom value for the selected specifier :
ps -o pid='Process_ID',tt=TTY,time,comm=Command

If the custom value is empty, no header is displayed, which is convenient to output process names only : ps -o comm=


List all running processes :

  • ps -elf
  • ps aux / ps faux (Their output is not equivalent as both command don't return the same amount of results (check it with : watch -n 1 -d 'echo "-elf : "$(ps -elf | wc -l);echo " aux : "$(ps aux | wc -l)'))
  • pstree

Display process tree :

ps -axfo pid,ppid,uname,cmd

View the hierarchy of a specific process (aka "climb" the process tree) :

pidToInvestigate=30845; showPidDetails() { local pid=$1; ps -o ppid,pid,args "$pid"; }; getPpid() { local pid=$1; ps -o ppid= -p "$pid" | awk '/[0-9]+/ {print $1}'; }; investigatePid() { local pid="$1"; ppid=$(getPpid "$pid"); showPidDetails "$ppid"; [ "$ppid" -ne '1' ] && investigatePid "$ppid"; }; showPidDetails "$pidToInvestigate"; investigatePid "$pidToInvestigate"

Display process tree :

ps -axfo pid,ppid,uname,cmd

List the 10 most CPU-hungry processes (source) :

ps -eo pcpu,pid,state,user,lstart,args | sort -k 1 -r | head -10

Find the amount of RAM (in KiB) used by a process :

normal command :
ps -C firefox-esr -o comm,rss
with the = hack to hide the header line :
ps -C firefox-esr -o rss=
in MiB :
  • ps -o comm,rss | awk '/firefox-esr/ {print $2 / 1024}'
  • echo "$(ps -C firefox-esr -o rss=) / 1024" | bc
  • let ramUsed=$(ps -C firefox-esr -o rss=)/1024; echo $ramUsed

Get extra information using the output formatting specifiers :

ps -p942 -o %cpu,%mem,lwp,nlwp,sgi_p,start,start_time,vsz,wchan,rss,user

Find zombies:

  • ps -e -o pid,ppid,args,state | grep -E 'Z$'
  • pgrep -r Z

More about zombies (source) :

Zombie processes are already dead, so they can't be killed. They are the consequence of malfunction (or programming defect) in their parent processes.
When a process finishes :
  1. its status changes to EXIT_ZOMBIE
  2. its parent process
    1. is notified of the termination of a child process by receiving the SIGCHLD signal
    2. is expected to read the child process' exit status and stats with wait(). During that time, the child process is a zombie.
  3. then the zombie process is completely removed from memory and from the process table
This happens almost instantly, which is why in normal conditions we may see no zombie processes.

Consequence of having zombies :

The footprint of a zombie is only the memory required to store its process descriptor, so zombies have no impact on system resources or performance : a few zombies are harmless. The only impact they _could_ have is that every zombie has its own PID, and PIDs are limited to 32768 (cat /proc/sys/kernel/pid_max). So an uncontrolled growth of the zombie population may exhaust the pool of PIDs.

Getting rid of zombies :

Zombies are dead processes. You cannot kill the dead, but here are a few things you can try :
  1. notify the parent process that one of its children died :
    • kill -s SIGCHLD PID_parentOfZombieProcess
    • kill -s SIGCHLD $(ps -o ppid= -p PID_zombieProcess)
    this has already been done automatically —and failed— so it's unlikely it will change anything, but it's a safe #1 thing to try
  2. kill the parent process
  3. the init process inherits the zombie process
  4. init periodically runs wait(), cleaning up its own zombie children

How to find the full path of a command returned by ps ?

  • ps -eF | awk '/binary/ {print $2}' | xargs -I pattern ls -l /proc/pattern/exe
  • The command above will show a ls: cannot access /proc/whateverPid/exe: No such file or directory because awk matches its own process, which doesn't exist anymore once piped to ls via xargs. To workaround this :
    ps -eF | awk '$11 ~ "binary" {print $2}' | xargs -I pattern ls -l /proc/pattern/exe
  • If there are MANY processes (possibly) running the same binary (e.g. when running Oracle), you can check this by sorting the displayed binaries :
    ps -eF | awk '$11 ~ "binary" {print $2}' | xargs -I pattern ls -l /proc/pattern/exe | awk '{print $NF}' | sort -u