A complete guide to Linux/Unix signals and process management. Learn how Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux work behind the scenes. Discover how to gracefully terminate processes, run tasks in the background, keep services alive after logout, and manage multiple sessions with tmux for efficient system administration.
1. Introduction
In the Linux/Unix world, processes are central to our interactions with the system. Whether running a simple command or deploying a complex application, we’re interacting with processes. Effectively managing and controlling these processes is an essential skill for every developer and system administrator. You might often use Ctrl+Cto stop a runaway script or to &toss a task into the background. But what exactly happens behind the scenes? The signal mechanism lies at the heart of it all. This article will take you deep into the Linux/Unix signal mechanism, explaining how Ctrl+C, Ctrl+Z, kill, pkilland work, analyzing nohupand , &how to keep processes running continuously in the background, and explaining tmuxhow to interact with them. Understanding this will help you more confidently manage your system.
2. Signals: Asynchronous communication between processes
What is a signal?
Think of a signal as an “interrupt” or “notification” sent by the operating system or another process to a target process. It’s an asynchronous communication method that tells a process, “Hey, something happened, and you might want to take care of it!” These events might be a user pressing a key, a hardware error, or another process requesting an action (like exiting).
2.2. Common signals and their meanings
Linux defines many signals, each of which has a number and a name (for example SIGINT). It is important to understand some common signals:
SIGINT(Signal number 2): Interrupt . This is the most familiar signal, usuallyCtrl+Ctriggered by the keyboard. It requests the process to interrupt the current operation.SIGQUIT(Signal number 3): Quit signal . UsuallyCtrl+\triggered by .SIGINTSimilar to , but also commonly used to instruct a process to exit and perform a core dump, which is convenient for debugging.SIGTSTP(Signal number 20): Terminal Stop signal . UsuallyCtrl+Ztriggered by . It requests the process to suspend execution (suspend), and the process state will change toStopped.SIGTERM(Signal number 15): Terminate . This iskillthe default signal for commands without arguments. It is a polite request for the process to clean up after itself and exit. Programs can catch this signal and perform custom cleanup logic.SIGKILL(Signal number 9): Kill signal . This is a “brutal” signal, executed directly by the kernel, used to forcibly terminate a process. A process cannot catch or ignore this signal, so it always kills the target process, but the process does not have a chance to clean up. This is a last resort.SIGHUP(Signal number 1): Hangup . Originally used to indicate that a modem connection had been disconnected, it is now typically sent to processes (including background processes) in the session associated with the controlling terminal when that terminal is closed. Many daemons use this signal to reload their configuration files.SIGCONT(Signal number 18): Continue signal . Used to resume a process that was suspended bySIGTSTPor . It is used within the and commands.SIGSTOPfgbg
2.3. Three ways a process responds to signals
When a process receives a signal (except for some special signals), it has three options:
- Perform the default action: Each signal has a system-defined default behavior. Common default behaviors include: terminate the process, ignore the signal, terminate with core dump, suspend the process, and resume the process. For example, the default behavior
SIGINTfor andSIGTERMis to terminate the process. - Ignore the signal: The process can explicitly tell the kernel: “I don’t care about this signal, just treat it as if it didn’t happen.”
- To capture the signal: A process can register a specific function (called a signal handler). When the signal is received, the kernel will suspend the current execution flow of the process and execute the signal handler function instead. After the execution is completed, the kernel will decide whether to resume the original execution flow based on the situation.
2.4. Special Signals: SIGKILL and SIGSTOP
Special emphasis should be placed on SIGKILL(9) and SIGSTOP(19), which are similar SIGTSTPbut cannot be caught. These two signals are “privileged” signals; they cannot be caught, ignored, or blocked by a process. The kernel directly performs the corresponding action (forcefully terminate or forcefully suspend) on the target process. This ensures that the system administrator always has a way to control any uncontrolled process (except for the rare cases where the process is in a special kernel state).
3. Interactive Process Control: Keyboard Shortcuts
The most commonly used process control method in the terminal is keyboard shortcuts.
3.1. Ctrl+C: Send SIGINT
- How it works: When you press in the terminal
Ctrl+C, the terminal device driver captures this key combination and sends a signal to all processes in the foreground process groupSIGINT. - Default behavior: The default behavior of most interactive programs (such as scripts and command-line tools) is to terminate execution after receiving
SIGINT. - Application scenario: This is the most common way to stop the current command or program, such as stopping a long-running
pingcommand or a stuck script.

3.2. Ctrl+Z: Send SIGTSTP
- How it works: Similarly,
Ctrl+Zwhen you press , the terminal driver sendsSIGTSTPa signal to the foreground process group. - Default behavior: The process that receives
SIGTSTPsuspends its execution (is suspended) and put into the background. The shell displays[1]+ Stopped my_commanda message similar to . - Application scenario: This is useful when you want to temporarily pause a foreground task (such as a compilation process) to execute another command and then return to the task. You can use
jobsto view the suspended task, usebg %job_idto resume it in the background, or use tofg %job_idbring it back to the foreground to resume it.

4. Command line process control: kill and pkill
When a process runs in the background, or you want more precise control over the process, you need command-line tools.
4.1. kill Command
- grammar:
kill [-s signal | -signal] <PID> ... - Function:
killThe core function of this command is to send a signal to the specified process ID (PID). You need to find the PID of the target process using commands such asps, ,pgrepor .top - Default signal: If no signal is specified, the
kill <PID>defaultSIGTERMsignal (15) is sent to request the process to exit gracefully. - Common signals:
kill -9 <PID>Orkill -SIGKILL <PID>: SendSIGKILL(9) signal to force the process to terminate. This is a common method for dealing with zombie processes or unresponsiveSIGTERMprocesses.kill -1 <PID>Orkill -SIGHUP <PID>: SendSIGHUP(1) signal, often used to notify the daemon to reload the configuration.kill -CONT <PID>Orkill -18 <PID>: SendSIGCONT(18) signal to resume theSIGTSTPsuspendedSIGSTOPprocess.
- Application scenario: accurately send a specific signal to a process with a known PID to implement operations such as graceful stop, forced stop, reload configuration, and resume operation.
4.2. pkill Command
- grammar:
pkill [options] <pattern> - Function:
pkillGoing a step further, it allows you to match processes based on process name or other attributes (such as username-u user, full command line-f) and send signals to all matching processes. - Default signal: Again, the default is sent
SIGTERM(15). - The difference from
kill:killoperates based on exact PID, whilepkillsearches for processes based on pattern matching. - Application scenarios: This is very convenient when you are unsure of the PID or want to batch process processes with the same name. For example,
pkill firefox` will attempt to terminate allfirefoxprocesses named ` `.pkill -9 -f my_buggy_script.py` will forcibly kill allmy_buggy_script.pyprocesses whose command lines contain ` `. Be extremely careful when usingpkill` ` to ensure that your pattern does not accidentally damage other important processes.
5. Background execution and continuous operation: & and nohup
Sometimes we need to run a time-consuming task but don’t want it to block the current terminal.
5.1. & Operator: Putting a Process into Background Execution
- How it works: Adding “/” to the end of a command
&, for examplemy_long_task &, causes the shell to start the command but not wait for it to complete. Instead, it returns to the command prompt immediately, allowing you to continue entering other commands. The process runs in the background. The shell prints the job ID and PID of the background task. - Problem: Background processes started in this way remain associated with the current terminal session. When you close the terminal (exit the shell), the system typically sends
SIGHUPa signal to all processes in that terminal session, including the background process. Unless otherwise specifiedSIGHUP, the default behavior is to terminate the process. Furthermore, the process’s standard input, output, and error streams may still be connected to the (soon-to-be-closed) terminal, potentially causing problems or unexpected behavior. - Application scenario: Quickly start a task and immediately release the terminal for non-critical background tasks that can be interrupted.
5.2. nohup command: ignore SIGHUP signal
- Working principle:
nohupThe command is used to run a specified command and make it ignoreSIGHUPthe signal. Its syntax isnohup command [arg...]. When younohupstart a command with , even if you close the terminal that started it, the command will notSIGHUPexit due to receiving the signal. - Output redirection: By default,
nohupthe command’s standard output (stdout) and standard error (stderr) are redirected to files in the current directorynohup.out. If the current directory is not writable, it will try to redirect them there$HOME/nohup.out. You can also redirect the output manually, for examplenohup my_command > my_output.log 2>&1. - Purpose: Ensure that the process continues to run after you log out or close the terminal.
5.3. Golden combination: nohup command &
- Explanation: Combining
nohupand&is the most common way to reliably run a command in the background.nohup command [arg...] &.nohupensures that the command ignoresSIGHUPthe signal,&then puts the command into the background for execution, returning immediately to the terminal prompt. - Application scenarios: deploy services that need to run for a long time, execute time-consuming batch tasks, and run any program that you want to keep running after you disconnect.
6. Process Behavior: Signal Handling and Default Responses
Now, let’s explore how programs interact with signals internally.
6.1. What happens if a program does not explicitly write signal handling logic?
- Explanation: Very simple, the process will perform the default action for the signal .
- Received
SIGINT(Ctrl+C),SIGTERM(kill <PID>),SIGQUIT(Ctrl+\): The default is usually to terminate the process. - Received
SIGTSTP(Ctrl+Z): The default is to pause (suspend) the process. - Received
SIGHUP(terminal closed): The default is to terminate the process. - Received
SIGKILL(kill -9 <PID>): By default, the process is always terminated (cannot be changed). - Received
SIGCONT(fg,bg,kill -CONT <PID>): The default is to resume the run (if it was previously paused).
- Received
- So, if your script or program does not handle this specially
SIGINT, pressingCtrl+Cit will exit directly.
6.2. Writing a Signal Handler (Using Python as an Example)
Most programming languages provide a mechanism for handling signals. In Python, you can use the signal handling signalmodule.
- Example code 1: Simple Python script, no signal processing
# simple_loop.py
import time
import os
print(f"Process ID: {os.getpid()}")
print("Running a simple loop... Press Ctrl+C to attempt interrupt.")
count = 0
while True:
count += 1
print(f"Loop iteration {count}")
time.sleep(1)
- test:
- run
python simple_loop.py. - according to
Ctrl+C.
- Expected behavior: The program terminates immediately and may display
^Ca message like . This is becauseSIGINTthe default behavior of is to terminate the process.
- run

- Example code 2: Python script, capture
# signal_handler_example.py
import signal
import time
import sys
import os
print(f"Process ID: {os.getpid()}")
print("Running loop with SIGINT handler. Press Ctrl+C.")
# Define signal handler function
def graceful_shutdown(signum, frame):
print(f"\nReceived signal {signum} ({signal.Signals(signum).name}). Cleaning up...")
# You can add your cleanup code here, such as saving status, closing files, etc.
print("Performing graceful shutdown steps...")
time.sleep(1) # Simulate cleanup operations
print("Cleanup complete. Exiting.")
sys.exit(0) # Graceful Exit
# Register a handler for SIGINT (Ctrl+C)
signal.signal(signal.SIGINT, graceful_shutdown)
# You can also catch SIGTERM (kill <PID>)
signal.signal(signal.SIGTERM, graceful_shutdown)
count = 0
while True:
count += 1
print(f"Loop iteration {count}. Still running...")
time.sleep(1)
# If you want the loop to end naturally after a certain condition, you can add a judgment here
# if count > 10:
# print("Loop finished normally.")
# break
- test:
- run
python signal_handler_example.py. - according to
Ctrl+C.
- Expected behavior: The program will not terminate immediately. Instead, it will print
Received signal 2 (SIGINT). Cleaning up...a message such as , execute the logic in the handler function, and then callsys.exit(0)exit.
- Open another terminal, find the PID of the script (the first line of output), and execute
kill <PID>(sendSIGTERM).
- Expected behavior: Again, the program will capture
SIGTERM, executegraceful_shutdownthe function, and then exit.
- run

6.3. How to force quit after catching a signal?
- Explanation: If a process catches
SIGINTorSIGTERMand does not choose to exit in its signal handler (or enters an infinite loop or stuck state), thenCtrl+Corkill <PID>cannot terminate it. At this time, we need the last resort:SIGKILL. - Demo:
- Modify the function
signal_handler_example.pyingraceful_shutdownso that it is not calledsys.exit(0), for example, it only prints a message:
- Modify the function
def stubborn_handler(signum, frame):
print(f"\nReceived signal {signum} ({signal.Signals(signum).name}). Haha, I caught it but I won't exit!")
# ... # You can add other operations here
signal.signal(signal.SIGINT, stubborn_handler)
signal.signal(signal.SIGTERM, stubborn_handler)
# ...
- Run the modified script
python signal_handler_example.py. PressCtrl+C. You will see it print the message but continue running. Execute in another terminalkill <PID>. It will still print the message and continue running. Now, executekill -9 <PID>. Or executeCtrl+\.
- Expected behavior: The process is immediately and forcefully terminated without any cleanup or goodbye messages. The terminal may display
Killed. This isSIGKILLthe power of .
- Run the modified script

Forced pause: SIGSTOP(Signal 19)
- Explanation: Similar
SIGKILLto the forced termination of ,SIGSTOPit is a forced pause signal. UnlikeSIGTSTP(Ctrl+Z),SIGSTOPit cannot be caught, blocked, or ignored by the process . You can send it viakill -STOP <PID>or .kill -19 <PID> - Use:
SIGTSTPUse when you want to immediately and unconditionally suspend the execution of a process (even if it is ignored)SIGSTOP. After the process is suspended, you can useSIGCONT(kill -CONT <PID>orkill -18 <PID>) to resume it. - Keyboard shortcuts: Again, there is no
SIGSTOPstandard keyboard shortcut assigned to .
A tougher interruption: SIGQUIT(Signal 3) withCtrl+\
- Explanation: As mentioned previously, is
SIGQUITtypicallyCtrl+\triggered by . WhileSIGQUITit can be caught or ignored by the process (unlikeSIGKILL/SIGSTOP), its default behaviorSIGINTdiffers from : it not only terminates the process but also typically generates a core dump file . This file is a snapshot of the process’s memory state at the time of termination and is very useful for post-mortem debugging. - Compulsory in practice: Due to the nature of generating core dumps, and
SIGINTthe fact that programs are less likely to specifically capture and handle themSIGQUITthan , in practice,Ctrl+\it is oftenCtrl+Cmore effective than to terminate some “reluctant” programs. - Use case: When
Ctrl+Cdoes not work, or you suspect the program crashes and want to get a core dump file to analyze the cause, you can try itCtrl+\. But remember that it is still not absolutely mandatory, if the process explicitly captures and ignores itSIGQUIT, it may also be ineffective.
When you need to stop a foreground process, try the following increasing order of force :
Ctrl+C(SIGINT) : Attempt graceful termination.Ctrl+\(SIGQUIT) : Try a tougher interrupt and possibly get a core dump.Ctrl+Z(SIGTSTP) : Pause the process, then you can usekill -9 %job_idor (need to find the PID with orkill -9 <PID>first ). For background processes or processes with known PIDs:jobspskill <PID>(SIGTERM) : Request a graceful exit.kill -QUIT <PID>(SIGQUIT) : A more forceful exit request, which may generate a core dump.kill -9 <PID>(SIGKILL) : Forced termination.
7. Terminal Multiplexer: tmux and Process Management
tmuxIt is a powerful tool that allows us to create and manage multiple virtual terminal sessions on a single physical terminal. Its relationship with process lifecycle and signals is worth exploring.
7.1. Introduction to tmux
tmuxTerminal Multiplexer (TM) allows you to have multiple independent shell sessions (windows and panes) within a single window and easily switch between them. Its key feature is session detachment (detach) and reattachment (attach) . You can start atmuxsession, run commands within it, thendetachclose your SSH connection or physical terminal, andattachreturn to it later to find your programs still running.
7.2. Effects of tmux exiting the current window/pane on the process
Here we need to strictly distinguish several tmuxways of “exit”:
- Detach: This is usually done using the shortcut key
Ctrl+Band then pressingd. This simply disconnects your client (your current terminal) fromtmuxthe server.tmuxThe server itself, along with all sessions, windows, panes, and processes it manages, continues to run in the background .detachNo signals are sent totmuxprocesses running within it. You can reconnect usingtmux attachor .tmux a - Close the pane/window (Exit/Kill):
- In the Shell window of the pane, type
exitor pressCtrl+D: This will end the Shell process. If this Shell is the only process in the pane, the pane will close. - Use
tmuxcommand:tmux kill-paneortmux kill-window. - Effect on processes: When a pane or window is closed, a signal
tmuxis normally sent to the foreground process group in that pane/windowSIGHUP. This behavior is similar to closing a normal terminal. Therefore, if the foreground process in the pane has no handlesSIGHUPor was notnohupstarted with , it will likely be terminated.
- In the Shell window of the pane, type
7.3. Running services inside tmux
Suppose you tmuxhave a service (such as a web server) running in a pane of the window:
- If the service is running in the foreground (eg,
python my_web_server.py) :- You
detach(Ctrl+B d): The service continues to run .tmuxThe server and the session are both up. - You enter in this pane
exitorCtrl+D(close the pane):tmuxmay bepython my_web_server.pysent toSIGHUP. If this Python server does not catch and handleSIGHUP(the default behavior is to terminate), then the server will stop .
- You
- If the service has been correctly backed/daemonized (eg,
nohup python my_web_server.py &, or the service has daemonization logic implemented within it) :- You
detach: The service continues to run . exitYou enter or in this paneCtrl+D: Even iftmuxsentSIGHUP, the service will continue to runnohupbecause the process was started with (ignoredSIGHUP) or has been detached from the terminal (daemonized) . Closing this pane has no effect on it.
- You
7.4. Sample code testing in tmux scenario
Let’s use the previous Python script tmuxto experiment in the environment:
- To start
tmux: Type in your terminaltmux. - Test
Ctrl+C(SIGINT):tmuxRuns in a pane (python simple_loop.pyno signal handling).- Press
Ctrl+C. Expected: process terminates, just like in a normal terminal. tmuxRun in a pane (python signal_handler_example.pycatch SIGINT).- Press
Ctrl+C. Expected: Execute signal handler, then exit (or act as per handler logic).
- Test
detachandattach:tmuxRun in a pod (python simple_loop.py &run in the background, but nothingnohup). Note the PID.detachSession (Ctrl+B d).- Go back to the normal terminal and check with
ps aux | grep pythonorps -p <PID>. Expected: the process is still running. attachReturn to the session (tmux attach).- You can use
fgto bring the background task back to the foreground and thenCtrl+Cstop it, or usekill <PID>.
- Test closing the pane (simulating SIGHUP):
tmuxRun in a pane (python simple_loop.pyforeground, no signal handling, nothingnohup). Note the PID.tmuxType in the paneexitor press toCtrl+Dclose the pane.- Go back to the other terminal (
tmuxor other pane/window of ) and check withps aux | grep pythonorps -p <PID>. Expected: The process has most likely terminated because it receivedSIGHUPand the default behavior is to exit.
- Test closing the pane (using
nohup):tmuxRun in the pod .nohup python simple_loop.py &Note the PID.tmuxType in the paneexitor press toCtrl+Dclose the pane.- Go back to the other terminal and check with
ps aux | grep pythonorps -p <PID>. Expected: The process is still running , but because it isnohupprotected by , it is ignoredSIGHUP. The output will go tonohup.outthe file.


8. Summary
We’ve delved into the signal mechanism, the core of Linux/Unix process control. Understanding the meaning and default behavior of key signals such as SIGINT, SIGTERM, SIGKILL, SIGHUP, and , SIGTSTPis crucial. We’ve seen how Ctrl+Cand Ctrl+Zinteract with foreground processes through signals, and learned how to use killand pkillto send signals to processes precisely or in batches. The combination of &and nohupensures reliable background execution. Finally, we analyzed tmuxthe process lifecycle in a [unclear context – likely a corrupted or corrupted file] environment, specifically detachthe different effects of and closing a window on a process. Mastering this knowledge will empower you to be more proficient in development and operations, write more robust programs, and effectively manage system resources.
9. Appendix
- List of commonly used signals (partial):
- 1:
SIGHUP(Hangup) - 2:
SIGINT(Interrupt) - 3:
SIGQUIT(Quit) - 9:
SIGKILL(Kill) - 15:
SIGTERM(Terminate) - 18:
SIGCONT(Continue) - 19:
SIGSTOP(Stop – cannot be caught or ignored) - 20:
SIGTSTP(Terminal Stop)
- 1:
- Related Commands
manManual Page Reference:man 7 signal(Detailed signal description)man 1 killman 1 pkillman 1 nohupman 1 tmuxman 2 signal(Programming interface)man psman jobs,man fg,man bg
FAQ
1.What is the difference between Ctrl+C and Ctrl+Z in Linux?
Ctrl+C sends a SIGINT signal to the foreground process, usually terminating it. Ctrl+Z sends a SIGTSTP signal, suspending the process and putting it into the background, which can later be resumed with fg or bg.
2.What is the difference between kill and pkill?
The kill command sends a signal to a process by its PID, while pkill can match processes based on names or attributes and send signals to multiple processes at once.
3.How do I keep a Linux process running after closing the terminal?
You can use the nohup command to ignore SIGHUP signals and combine it with & to run a process in the background, e.g., nohup my_command &. Another option is to use tmux, which allows detaching and reattaching terminal sessions without stopping processes.
4.What is the difference between SIGTERM and SIGKILL?
SIGTERM is a gentle termination request, allowing a process to clean up before exiting. SIGKILL is a forceful termination that cannot be caught or ignored, and it kills the process immediately without cleanup.
5.Why should I use tmux for process management?
tmux lets you create multiple sessions in a single terminal, detach and reattach them later. This ensures processes continue running even if your SSH session or terminal closes, making it ideal for long-running tasks and remote system administration.