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


Flag Usage
-a select all processes except both session leaders and processes not associated with a terminal
a lift the BSD-style "only yourself" restriction. Select all processes with a terminal. Select all processes when used with x
-A or -e select All processes
-C commandList select processes whose executable name is given in commandList
f forest : ASCII-art process hierarchy
-f full-format listing
-F extended full-format listing. Implies -f
l display BSD long format
-L Show Lthreads, possibly with LWP and NLWP columns
o formatSpecString
-o formatSpecString
--format formatSpecString
introduces the output formatting options
-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
U userId
-u userId
--user userId
select processed owned by userId (user name orUID)
Z Add a column of security data. Identical to -M (for SELinux)

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

Output format flags (source) :

Flag 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
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 : Running, Sleeping, Zombie, ...
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,flags
You can change a column header by specifying a custom value for the selected flag :
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 flags :

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$'

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 they parent processes. Here is how processes die :

  1. A process finishes, its status changes to EXIT_ZOMBIE.
  2. Its parent is notified of the termination of a child process by receiving the SIGCHLD signal.
  3. The parent process is expected to read the child process' exit status and stats with wait(). During that time, the child process is a zombie.
  4. Then the zombie process is completely removed from memory and from the process table.
This happens almost instantly, so in normal conditions, we may not see 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. What you can try, is to send the SIGCHLD signal to their parent process (but that obviously already failed once, so...). To effectively definitely remove a zombie process :
  1. Kill its parent process
  2. The init process inherits the zombie process
  3. 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