Skip to content

103.5 Create, monitor and kill processes

Weight: 4

Candidates should be able to perform basic process management.

Objectives

  • Run jobs in the foreground and background.
  • Signal a program to continue running after logout.
  • Monitor active processes.
  • Select and sort processes for display.
  • Send signals to processes.

Terms

&, bg, fg, jobs, kill, nohup, ps, top, free, uptime, killall, pgrep, pkill, watch, screen, tmux

Managing processes

foreground and background jobs

One of the great points of Linux even from its beginning days is the ability to run different programs and jobs at the same time. This is done by sending programs to the background.

Normally if you run a program on the terminal, it blocks your terminal while it is running, but sending a command to the background will prevent this:

xeyes &

Even when a program is running normally in the foreground, you can do two things:

  • break it using Ctrl+c
  • suspend or pause it using Ctrl+z

A stopped job can be brought to the foreground using the fg command, or to the background using bg. You can also list all the jobs with the jobs command.

$ xeyes
^Z
[1]+  Stopped                 xeyes
$ jobs
[1]+  Stopped                 xeyes
$ bg
[1]+ xeyes &
$ jobs
[1]+  Running                 xeyes &
$ sleep 1000 &
[2] 7395
$ jobs
[1]-  Running                 xeyes &
[2]+  Running                 sleep 1000 &
$ fg %2
sleep 1000
^Z
[2]+  Stopped                 sleep 1000
$ jobs
[1]-  Running                 xeyes &
[2]+  Stopped                 sleep 1000
$ bg sle
[2]+ sleep 1000 &
$ jobs
[1]-  Running                 xeyes &
[2]+  Running                 sleep 1000 &

jobs -l also shows the process ID of jobs.

The three states a job moves between:

                 Ctrl+z
   foreground  --------->  stopped
        ^                    |  |
        |  fg                |  |  bg
        |                    |  v
        +--------------------+  background
                 fg              (keeps running)

   &  starts a command directly in the background

Each part of a jobs line is worth knowing, because the symbols are easy to miss:

$ jobs
[1]+ Stopped sleep 60
  • [1] = the job ID. Put a % in front of it to refer to the job with fg, bg or kill.
  • + = the current, default job, meaning the last one suspended or backgrounded. The one before it is marked -. Older jobs get no mark at all.
  • Stopped = the status.
  • sleep 60 = the command itself.

With -l the PID appears too:

$ jobs -l
[1]+ 1114 Stopped sleep 60

A job ID and a PID are two different numbers. The job ID belongs to your shell and starts again at 1 in each shell. The PID belongs to the whole system.

The other jobs options: -n shows only jobs whose status changed since the last notification, -p lists only PIDs, -r lists only running jobs, and -s lists only stopped jobs.

There are also several ways to name a job, called a jobspec:

  • %n = job number n
  • %str = the job whose command line starts with str
  • %?str = the job whose command line contains str
  • %+ or %% = the current job
  • %- = the previous job

This is why bg sle works without a number. It matches the job starting with sle.

A small but testable detail: fg and bg act on the current job when you give them nothing, but kill always needs a jobspec.

Real world use for Ctrl+z then bg: you start a long copy in the foreground and realise you need the terminal back. Suspend it, send it to the background, and carry on working.

nohup

The nohup command lets you run your commands even after you close the terminal or log out. By default it writes its output to nohup.out:

$ nohup ping 4.2.2.4
nohup: ignoring input and appending output to 'nohup.out'
^C$ cat nohup.out
PING 4.2.2.4 (4.2.2.4) 56(84) bytes of data.
64 bytes from 4.2.2.4: icmp_seq=1 ttl=51 time=225 ms
64 bytes from 4.2.2.4: icmp_seq=3 ttl=51 time=223 ms

--- 4.2.2.4 ping statistics ---
4 packets transmitted, 2 received, 50% packet loss, time 3010ms
rtt min/avg/max/mdev = 223.584/224.767/225.950/1.183 ms

It is common to use 2> to redirect the nohup errors to another file and use a & to run it in the background: nohup script.sh > mynohup.out 2>&1 &

The name means "no hangup". When you close a terminal, the shell sends the HUP signal to its jobs and they die. nohup makes the process ignore that signal, so it survives:

   normal job:   close terminal --> HUP signal --> job dies

   nohup job:    close terminal --> HUP signal --> ignored,
                                                   job keeps
                                                   running

The full round trip, including checking on it from a new session:

$ nohup ping localhost &
[1] 1251
$ nohup: ignoring input and appending output to 'nohup.out'
^C
$ exit
logout
$ tail -f /home/carol/nohup.out
64 bytes from localhost (::1): icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from localhost (::1): icmp_seq=4 ttl=64 time=0.068 ms
64 bytes from localhost (::1): icmp_seq=5 ttl=64 time=0.070 ms
^C

Since the shell that started it is gone, the job ID is gone with it. Killing it now needs the PID:

# kill 1251

You can also choose your own output file instead of nohup.out, with nohup ping localhost > /path/to/your/file &.

Real world use: starting a long database import over ssh on a server. Without nohup, a dropped connection kills the import halfway through.

kill

Despite its frightening name, the kill command sends unix signals to processes. Pressing Ctrl+c and Ctrl+z is also sending signals. By default, the kill command sends the signal 15, which is TERM and tells the process to stop itself.

$ jobs
[3]   Running                 xeyes &
[4]   Running                 sleep 1000 &
[5]-  Running                 sleep 2000 &
[6]+  Running                 sleep 3000 &
$ kill %4
$ jobs
[3]   Running                 xeyes &
[4]   Terminated              sleep 1000
[5]-  Running                 sleep 2000 &
[6]+  Running                 sleep 3000 &
$ jobs
[3]   Running                 xeyes &
[5]-  Running                 sleep 2000 &
[6]+  Running                 sleep 3000 &

Note that job 4 shows as Terminated once, then disappears from the list entirely on the next jobs call. The shell reports the change only once.

It is also possible to use PIDs instead of job numbers, and to send other signals. The general format is kill -SIGNAL_ID_OR_NAME process_id:

signal number signal name meaning
1 HUP Informing the process that its controlling terminal (like an ssh connection) is terminated
15 TERM normal termination request
9 KILL forcefully kills the process

So you can do a kill -9 8733 to force process ID 8733 to close.

Remember the nohup command? It means "do not respond to the hup signal".

The difference between 15 and 9 is the one to understand:

   kill -15 (TERM)     asks the process to stop.
                       The process can catch this signal,
                       save its files, close connections,
                       then exit cleanly.

   kill -9 (KILL)      the kernel removes the process.
                       The process cannot catch or ignore it.
                       No cleanup happens. Data can be lost.

Always try 15 first. Use 9 only when a process refuses to respond.

There are three ways to name a signal, and they all do the same thing:

$ kill -SIGHUP 1247
$ kill -1 1247
$ kill -s SIGHUP 1247

For the full list of signals on your system, run kill -l.

You can also combine kill with pgrep using command substitution, so you do not have to look up the PID first:

$ kill -1 $(pgrep sleep)

killall

This command will send the given signal, or by default 15, to all processes with the given name:

$ jobs
[3]   Running                 xeyes &
[5]-  Running                 sleep 2000 &
[6]+  Running                 sleep 3000 &
$ ps -ef | grep sleep
nagato    7864  7651  0 21:07 pts/1    00:00:00 sleep 2000
nagato    7865  7651  0 21:07 pts/1    00:00:00 sleep 3000
nagato    7977  7651  0 21:14 pts/1    00:00:00 grep sleep
$ killall sleep
[5]-  Terminated              sleep 2000
[6]+  Terminated              sleep 3000
$ jobs
[3]+  Running                 xeyes &
$ ps -ef | grep sleep
nagato    7980  7651  0 21:14 pts/1    00:00:00 grep sleep

Notice the grep sleep line appearing in the ps output both times. That is the grep command itself, which contains the word sleep in its own command line. This is a normal and slightly confusing artefact of ps -ef | grep something.

pkill

Will send the given signal, or 15, to all the processes with a specific pattern in their name:

$ jobs
[3]   Running                 xeyes &
[5]-  Running                 sleep 2000 &
[6]+  Running                 sleep 3000 &
$ ps -ef | grep sleep
nagato    7864  7651  0 21:07 pts/1    00:00:00 sleep 2000
nagato    7865  7651  0 21:07 pts/1    00:00:00 sleep 3000
nagato    7977  7651  0 21:14 pts/1    00:00:00 grep sleep
$ pkill sle
[5]-  Terminated              sleep 2000
[6]+  Terminated              sleep 3000
$ jobs
[3]+  Running                 xeyes &
$ ps -ef | grep sleep
nagato    7980  7651  0 21:14 pts/1    00:00:00 grep sleep

The difference between the three killing commands, since they overlap:

   kill      needs a PID or a jobspec.     kill 7864   kill %5
   killall   matches the exact name.       killall sleep
   pkill     matches a pattern in the name. pkill sle

pkill sle worked where killall sle would not, because killall wants the whole name. That extra reach is also the danger. pkill ssh would match sshd too, and could lock you out of a server.

Monitoring Processes

ps

The ps command shows running processes on your computer. Each process has a process ID shown as PID and a Parent Process ID shown as PPID.

$ sleep 1000 &
[1] 7678
$ sleep 1001 &
[2] 7679
$ xeyes &
[3] 7680
$ ps
  PID TTY          TIME CMD
 7651 pts/1    00:00:00 bash
 7678 pts/1    00:00:00 sleep
 7679 pts/1    00:00:00 sleep
 7680 pts/1    00:00:00 xeyes
 7681 pts/1    00:00:00 ps

Note that plain ps only shows processes from this terminal. 7651 is the bash that is the parent of everything else here, and 7681 is the ps command reporting on itself.

Two common switch combinations are ps aux (or -aux) and ps ef, which show ALL processes on a system:

$ ps -aux | wc -l
293

It is also possible to use the --sort switch to sort the output based on different fields (+ for ascending and - for descending).

$ ps -af --sort +comm,-sid
UID        PID  PPID  C STIME TTY          TIME CMD
root      5486  5478  0 19:59 pts/12   00:00:00 -su
root      4444  1169  0 19:56 tty4     00:00:00 -bash
nagato    6638  5412  0 20:10 pts/0    00:00:04 node /usr/local/bin/sslocal
nagato    7778  7651  0 20:58 pts/1    00:00:00 ps -af --sort +comm,-sid
nagato    7678  7651  0 20:48 pts/1    00:00:00 sleep 1000
nagato    7679  7651  0 20:48 pts/1    00:00:00 sleep 1001
nagato    7775  7651  0 20:58 pts/1    00:00:00 sleep 1000
nagato    7776  7651  0 20:58 pts/1    00:00:00 sleep 1000
nagato    7777  7651  0 20:58 pts/1    00:00:00 sleep 1000
root      5478  5477  0 19:59 pts/12   00:00:00 su -
root      5477  5008  0 19:59 pts/12   00:00:00 sudo su -
nagato    7680  7651  0 20:48 pts/1    00:00:01 xeyes

Something that catches people out: ps accepts three different option styles, and they behave differently.

BSD     no dash        ps p 811
UNIX    one dash       ps -p 811
GNU     two dashes     ps --pid 811

All three ask about PID 811, but the output columns differ:

$ ps p 811
  PID TTY STAT TIME COMMAND
  811 pts/0 S 0:00 -su
$ ps -p 811
  PID TTY TIME CMD
  811 pts/0 00:00:00 bash

The BSD form added a STAT column. This is exactly why ps aux is written without a dash while ps -ef is written with one. They are not typos, they are two different styles.

The same three styles apply for filtering by user: ps U carol, ps -u carol or ps --user carol.

What aux actually means:

  • a = show processes attached to a terminal
  • u = user oriented format
  • x = show processes not attached to a terminal
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 204504 6780 ? Ss 14:04 0:00 /sbin/init
root 2 0.0 0.0 0 0 ? S 14:04 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 14:04 0:00 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< 14:04 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S 14:04 0:00 [rcu_sched]
root 8 0.0 0.0 0 0 ? S 14:04 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S 14:04 0:00 [migration/0]

Reading the columns: VSZ is virtual memory in KiB, RSS is the non-swapped physical memory actually in RAM, TTY is the controlling terminal (? means none), and STAT is the state code.

The STAT codes worth knowing:

  • S = interruptible sleep, waiting for something
  • R = runnable, either running or queued to run
  • Z = zombie, finished but its parent has not collected it yet
  • D = uninterruptible sleep, usually waiting on disk I/O
  • T = stopped

And the modifiers that can follow: < high priority, N low priority, + in the foreground process group. The names in square brackets, like [kthreadd], are kernel threads rather than normal programs.

pgrep

You have seen that ps -ef shows processes from all users. We can grep on that and see who is running gedit and what its process ID is:

$ ps -ef | grep gedit
nagato    6213  4604  9 20:06 ?        00:04:43 gedit
nagato    7725  7651  0 20:55 pts/1    00:00:00 grep gedit

but there is also a more direct way to check the PID of all gedit processes:

$ pgrep gedit
6213

Compare the two outputs. pgrep gave just the number, with no extra grep line polluting the result. That is why it is the better tool when you want to feed the PID into another command.

A second command does nearly the same thing: pidof, as in pidof sleep.

top

This is the most common tool to do simple monitoring of the system. It will update the status and give you a good glance at the status:

$top

top - 21:00:44 up  1:16,  5 users,  load average: 1.51, 1.65, 1.78
Tasks: 293 total,   1 running, 292 sleeping,   0 stopped,   0 zombie
%Cpu(s): 19.0 us,  5.0 sy,  0.0 ni, 70.9 id,  5.1 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   8060264 total,  5359812 used,  2700452 free,   169240 buffers
KiB Swap:  7811068 total,        0 used,  7811068 free.  2250692 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND  
 6570 nagato    20   0 1437752 546064  88312 S  18.4  6.8  12:00.96 firefox  
 4870 nagato    20   0 1762516 299120  75664 S  12.2  3.7   7:37.05 compiz  
 4492 nagato     9 -11  455152  11516   8940 S   6.1  0.1   1:06.81 pulseaudio  
 4532 root      20   0  389028  77116  60192 S   6.1  1.0  12:16.63 Xorg  
 4723 nagato    20   0  358936   8288   5512 S   6.1  0.1   9:51.52 ibus-daemon  
 5648 nagato    20   0 1641556 203676 102840 S   6.1  2.5   3:20.88 chrome  
 7082 nagato    20   0 1210748  73136  42528 S   6.1  0.9   0:36.51 Telegram  
 7806 nagato    20   0   33796   3004   2500 R   6.1  0.0   0:00.02 top  
    1 root      20   0   29528   4320   2584 S   0.0  0.1   0:01.71 init

You can see the processes, system load, uptime, CPU status and memory, and do some stuff:

key during top functionality
h help
q quit
M sort based on memory usage
c show full commands
k kill after asking pid and signal

A fuller list of interactive keys:

  • M sort by memory, N sort by PID, T sort by running time, P sort by CPU percentage
  • R reverse the sort order
  • ? or h help
  • k kill a process, it asks for the PID and the signal
  • r renice a process, it asks for the nice value. Only root can set a negative value or lower an existing one.
  • u show only one user's processes
  • c show full command paths, with kernel processes in square brackets
  • V forest view, showing the parent and child tree
  • t and m cycle the look of the CPU and memory readings
  • W save your settings to ~/.toprc

The display has two areas. Here is every field.

The summary area, the top five rows:

   top - 21:00:44 up 1:16, 5 users, load average: 1.51, 1.65, 1.78
         |         |       |                     |
         time      uptime  logged in users       1, 5 and 15 min load

   Tasks: 293 total, 1 running, 292 sleeping, 0 stopped, 0 zombie

A zombie is a process that finished but whose parent has not yet removed it from the process table. A few are harmless, many mean a badly behaved parent program.

The %Cpu(s) line splits CPU time into eight parts:

  • us user processes
  • sy system and kernel processes
  • ni processes with a changed nice value
  • id idle, doing nothing
  • wa waiting for disk or network I/O
  • hi serving hardware interrupts
  • si serving software interrupts
  • st steal time, time given to another virtual machine on the same host

That wa figure is the useful one for troubleshooting. A high wa with low us means the CPU is fine and the disk is the bottleneck.

The task area columns:

  • PID process identifier
  • USER who started it
  • PR priority as the kernel sees it
  • NI nice value, lower means higher priority (this is objective 103.6)
  • VIRT total memory used including swap
  • RES actual RAM used
  • SHR memory shared with other processes
  • S state, the same S, R, Z codes as ps
  • %CPU and %MEM percentages
  • TIME+ total CPU time used
  • COMMAND the program name

htop and atop are friendlier alternatives if your system has them.

free

The free command will show you info about the system memory. The default is kilobytes but you can change it with -m for megabytes, -g for gigabytes or even -b for bytes. You can also use -h for human readable.

$ free -m
             total       used       free     shared    buffers     cached
Mem:          7871       5231       2640        332        169       2195
-/+ buffers/cache:       2866       5005
Swap:         7627          0       7627

A general hint: if your system is using Swap, you have memory issues.

That second row, -/+ buffers/cache, is the one that matters. The first row says 5231 MB used, which looks alarming. But much of that is buffers and cache, memory Linux borrowed to speed up disk access and will hand back the moment a program needs it. The second row shows the honest figure: 2866 MB really in use and 5005 MB really available.

uptime

The uptime command shows the time, the system's uptime (how long the system has been running), how many users are logged in, and the load average of 1, 5 and 15 minutes:

$ uptime
 21:18:52 up  1:34,  5 users,  load average: 2.38, 2.64, 2.41

Although it is one of the most important KPIs of the system status, some experienced Linux admins do not know what the load average means. The load average shows how many processes are in the to be run queue. If this number is higher than the number of your CPU cores, you are in a bad situation. If it is close to the number of your cores constantly, it is kind of dangerous, and if it is less than a tenth of your core number, your system is kind of idle. Do you remember how to check the number of your cores? It is in /proc/cpuinfo or nproc.

The three numbers are 1, 5 and 15 minute averages, and comparing them tells you the direction:

   load average: 2.38, 2.64, 2.41
                  |     |     |
                  1min  5min  15min

   1min lower than 15min  -->  load is falling, the spike is over
   1min higher than 15min -->  load is rising, something is starting

watch

Sometimes you have a command which shows you an output but you want to keep running it and observing the output. In these cases, watch is your friend. It lets you run and check the output of a command at specific time intervals (default is 2 seconds).

$ watch free -h

If you have a pipe in your command, you have to quote the watched command in double quotes " or single quotes ':

$ watch "ls -ltrh | wc -l"

The quoting matters for the reason covered in 103.1. Without quotes, bash gives the pipe to your shell instead of to watch, so only the first part gets repeated.

These are some of the switches:

  • -n To specify the interval in seconds
  • -b Beep if the command has a non-zero exit
  • -d Shows the difference between runs

What the output actually looks like, with the extra header line watch adds:

Every 2.0s: uptime debian: Tue Aug 20 23:31:27 2019
 23:31:27 up 21 min, 1 user, load average: 0.00, 0.00, 0.00

The first line is from watch itself, telling you the interval, the command, the hostname and the date. The second line is the real output of uptime. It keeps running until you press Ctrl+C.

Real world use for -d: watching a directory fill up during a large transfer. watch -d "ls -l /var/spool" highlights exactly what changed between refreshes, so you see progress without reading the whole listing each time.

Terminal Multiplexers

screen

If you are used to a GUI based system, it is easy to run different terminals side by side and use them to run different programs. But if you are on a server, you need other tools to multiplex your terminal. One such command is screen.

Run it with screen and press enter to exit the welcome window into a prompt. You can use it as a normal terminal and detach from it, letting it run in the background, using the Ctrl + A and then D keys. Check the list of your screens with screen -ls and re-attach to any of them with screen -r screen-id.

Below you can see a few common switches. They all should be issued after the Ctrl + A combination.

Key Usage
\ Kill all processes windows and end the screen
| Split current window into two vertical focuses
Shift+S Split current window into two horizontal focuses
C Create a window in the current focus
Tab Go to the next focus
D Detach from window
K Kill current window
N Move to Next window
P Move to the Previous window

A great point about screen, and tmux, is the fact that it remains running even after you log out of the system, and it is possible to log in again and re-attach to the same screen or tmux.

The layered structure makes the commands easier to remember:

   session
     |
     +-- window          (runs a program)
     |     |
     |     +-- region    (a split view inside the window)
     |     +-- region
     |
     +-- window

Sessions detach and survive, windows hold programs, regions just divide the screen.

A worked walkthrough of windows:

$ screen
0*$ bash

That is the window list after Ctrl + a w. Counting starts at 0, and the asterisk marks the visible one. After creating a second window with Ctrl + a c:

0-$ bash 1*$ bash

Both are named bash since that is what is running. Rename the current one with Ctrl + a A, or create one with a name from the start:

$ screen -t yetanotherwindow

Then Ctrl + a " lists them for selection:

Num Name Flags
  0 bash $
  1 ps $
  2 yetanotherwindow

For sessions, listing and naming:

$ screen -list
There is a screen on:
  1037.pts-0.debian (08/24/19 13:53:35) (Attached)
1 Socket in /run/screen/S-carol.
$ screen -S "second session"
$ screen -ls
There are screens on:
  1090.second session (08/24/19 14:38:35) (Attached)
  1037.pts-0.debian (08/24/19 13:53:36) (Attached)
2 Sockets in /run/screen/S-carol.

Killing a session by name or PID:

$ screen -S 1037 -X quit

Detaching with Ctrl + a d prints a confirmation and returns you to your normal terminal:

[detached from 1090.second session]
$

The reattach options are worth knowing, because -r alone fails if the session is attached elsewhere:

  • -d -r detach it from wherever it is, then reattach here
  • -d -R same, and create the session if it does not exist
  • -d -RR same, but use the first session if several exist
  • -D -r detach and log out the remote user first
  • -d -m start a session detached without attaching, useful in startup scripts

Copy mode, for selecting text with the keyboard: Ctrl + a [ enters it, arrow keys move, Space marks the start, Space again marks the end, and Ctrl + a ] pastes.

Configuration lives in /etc/screenrc system wide, or ~/.screenrc per user. It holds settings like defscrollback 1024, key rebindings like bind l kill, and startup commands like screen -t top top. You can even change the command prefix itself with a line like escape ^Bb.

tmux

This is screen on steroids. It is not installed by default in most distributions and you have to install it first. The default command prefix is Ctrl+B and after running tmux new you can issue these:

Key Usage
% Split current window vertically
" Split current window horizontally
D Detach from the current window
& Kill current window

You can list the tmux sessions using tmux ls and re-attach to one using tmux att to connect to the last one, or tmux att -t session_name to attach to a specific one.

What tmux adds over screen: a client and server model where one server holds many sessions, interactive menus for picking sessions and windows, the ability to link one window to several sessions, both vim and Emacs key layouts, and UTF-8 with 256 colour support.

tmux shows a status bar at the bottom, which screen does not:

[LPI] 0:Window zero- 1:bash* "debian" 19:02 27-Aug-19
  |      |                |
  |      |                +-- window 1, the asterisk = visible now
  |      +-- window 0, the minus = previous window
  +-- session name

One nice difference: tmux renames a window automatically to match whatever is running in it, so starting top changes the name to top. screen keeps whatever name you gave it.

Naming a session and window at creation:

$ tmux new -s "LPI" -n "Window zero"

The fuller key list. Windows: Ctrl + b c create, Ctrl + b , rename, Ctrl + b w list, Ctrl + b n next, Ctrl + b p previous, Ctrl + b & kill, Ctrl + b f find by name.

Panes: Ctrl + b " split horizontally, Ctrl + b % split vertically, Ctrl + b plus an arrow key to move between them, Ctrl + b x kill the current pane, Ctrl + b z zoom one pane to fill the window, Ctrl + b { and } swap panes, Ctrl + b ! turn a pane into its own window.

An important difference from screen: a tmux pane is a complete pseudo-terminal, so killing a pane kills the programs inside it. A screen region is only a view, so removing it leaves its window alive.

Sessions:

$ tmux ls
LPI: 2 windows (created Tue Aug 27 19:01:49 2019) [158x39] (attached)
$ tmux kill-session -t "Second Session"
[exited]
$ tmux a

Detaching with Ctrl + b d:

[detached (from session LPI)]
$

If a session might already be attached somewhere else, tmux attach -d -t SESSION-NAME detaches it there first.

Copy mode works like screen's, but you mark the start with Ctrl + Space and copy with Alt + w.

Configuration lives in /etc/tmux.conf or ~/.tmux.conf, and tmux -f can point at a different file. There is usually an example at /usr/share/doc/tmux/example_tmux.conf. A common customization is changing the prefix key:

# Change the prefix key to C-a
set -g prefix C-a
unbind C-b
bind C-a send-prefix

Real world use: running a long deploy on a remote server inside tmux. If your laptop sleeps or the network drops, the deploy keeps going, and tmux a puts you back where you were.

Summary

I have a Linux system running many processes at once, and each one has a PID plus a parent PID that says which process started it. When I start something from my shell it is also a job, with its own small job number that only means something inside that shell. Adding & starts a command straight into the background, Ctrl+z suspends one that is already running, and fg and bg move it between the foreground and background. jobs lists them, and jobs -l adds the real PID next to each one.

To stop a process I send it a signal with kill. The default is signal 15, TERM, which asks the program to shut itself down properly. Signal 9, KILL, cannot be caught or ignored, so the process disappears immediately with no chance to save anything, and I keep that one for when 15 has failed. Signal 1, HUP, is what a closing terminal sends, and nohup exists precisely so a job can ignore it and keep running after I log out. When I do not want to look up a PID first, killall matches a whole process name and pkill matches part of one, though that partial matching needs care since a short pattern can hit more than I meant.

For watching what is happening, ps gives me a still picture and top gives me a live one. ps is unusual in accepting three different option styles, which is why ps aux has no dash while ps -ef does. In both tools the columns I care about are RES for real memory, %CPU, and the state code where S is sleeping, R is runnable and Z is a zombie waiting for its parent to clean it up. free shows memory, and the buffers and cache row is the honest one to read. uptime gives me the load average over 1, 5 and 15 minutes, which counts processes waiting to run and should stay below my core count. pgrep finds a PID cleanly, and watch repeats any command every couple of seconds so I can see a number change.

When I work on a server I use a terminal multiplexer so my work survives a dropped connection. screen and tmux both give me sessions holding windows, and windows split into regions or panes. The key idea in both is detaching: the session keeps running without a terminal attached, and I reconnect later with screen -r or tmux a. screen uses Ctrl+a as its prefix and tmux uses Ctrl+b, and each reads its settings from a file in /etc or my home directory. The difference worth remembering is that a tmux pane is a real terminal, so closing it kills what is inside, while a screen region is only a view onto a window that carries on.