Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

61 Views
No Comments

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+CCtrl+Zkillpkilland 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, usually Ctrl+Ctriggered by the keyboard. It requests the process to interrupt the current operation.
  • SIGQUIT(Signal number 3): Quit signal . Usually Ctrl+\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 . Usually Ctrl+Ztriggered by . It requests the process to suspend execution (suspend), and the process state will change to Stopped.
  • SIGTERM(Signal number 15): Terminate . This is killthe 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 by SIGTSTPor . 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:

  1. 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 and SIGTERMis to terminate the process.
  2. 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.”
  3. 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 group SIGINT.
  • 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.
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

3.2. Ctrl+Z: Send SIGTSTP

  • How it works: Similarly, Ctrl+Zwhen you press , the terminal driver sends SIGTSTPa 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, use bg %job_idto resume it in the background, or use to fg %job_idbring it back to the foreground to resume it.
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

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: kill The 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 as ps, , pgrepor .top
  • Default signal: If no signal is specified, the kill <PID>default SIGTERMsignal (15) is sent to request the process to exit gracefully.
  • Common signals:
    • kill -9 <PID>Or kill -SIGKILL <PID>: Send SIGKILL(9) signal to force the process to terminate. This is a common method for dealing with zombie processes or unresponsive SIGTERMprocesses.
    • kill -1 <PID>Or kill -SIGHUP <PID>: Send SIGHUP(1) signal, often used to notify the daemon to reload the configuration.
    • kill -CONT <PID>Or kill -18 <PID>: Send SIGCONT(18) signal to resume the SIGTSTPsuspended SIGSTOPprocess.
  • 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: pkill Going 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: kill operates based on exact PID, while pkillsearches 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 all firefoxprocesses named ` `. pkill -9 -f my_buggy_script.py` will forcibly kill all my_buggy_script.pyprocesses whose command lines contain ` `. Be extremely careful when using pkill` ` 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 example my_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 specified SIGHUP, 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: nohup The command is used to run a specified command and make it ignore SIGHUPthe signal. Its syntax is nohup command [arg...]. When you nohupstart a command with , even if you close the terminal that started it, the command will not SIGHUPexit 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 directory nohup.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 example nohup 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 ignores SIGHUPthe 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(fgbgkill -CONT <PID>): The default is to resume the run (if it was previously paused).
  • So, if your script or program does not handle this specially SIGINT, pressing Ctrl+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:
    1. run python simple_loop.py.
    2. according to Ctrl+C.
    • Expected behavior: The program terminates immediately and may display ^Ca message like . This is because SIGINTthe default behavior of is to terminate the process.
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide
  • 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:
    1. run python signal_handler_example.py.
    2. 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 call sys.exit(0)exit.
    1. Open another terminal, find the PID of the script (the first line of output), and execute kill <PID>(send SIGTERM).
    • Expected behavior: Again, the program will capture SIGTERM, execute graceful_shutdownthe function, and then exit.
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

6.3. How to force quit after catching a signal?

  • Explanation: If a process catches SIGINTor SIGTERMand does not choose to exit in its signal handler (or enters an infinite loop or stuck state), then Ctrl+Cor kill <PID>cannot terminate it. At this time, we need the last resort: SIGKILL.
  • Demo:
    1. Modify the function signal_handler_example.pyin graceful_shutdownso that it is not called sys.exit(0), for example, it only prints a message:
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)
# ...
    1. Run the modified script python signal_handler_example.py. Press Ctrl+C. You will see it print the message but continue running. Execute in another terminal kill <PID>. It will still print the message and continue running. Now, execute kill -9 <PID>. Or execute Ctrl+\.
    • Expected behavior: The process is immediately and forcefully terminated without any cleanup or goodbye messages. The terminal may display Killed. This is SIGKILLthe power of .
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

Forced pause: SIGSTOP(Signal 19)

  • Explanation: Similar SIGKILLto the forced termination of , SIGSTOPit is a forced pause signal. Unlike SIGTSTP(Ctrl+Z), SIGSTOP it cannot be caught, blocked, or ignored by the process . You can send it via kill -STOP <PID>or .kill -19 <PID>
  • Use:SIGTSTP Use 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 use SIGCONT(kill -CONT <PID>or kill -18 <PID>) to resume it.
  • Keyboard shortcuts: Again, there is noSIGSTOP standard keyboard shortcut assigned to .

A tougher interruption: SIGQUIT(Signal 3) withCtrl+\

  • Explanation: As mentioned previously, is SIGQUITtypically Ctrl+\triggered by . While SIGQUIT it can be caught or ignored by the process (unlike SIGKILLSIGSTOP), its default behavior SIGINTdiffers 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 them SIGQUITthan , in practice, Ctrl+\it is often Ctrl+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 it Ctrl+\. But remember that it is still not absolutely mandatory, if the process explicitly captures and ignores it SIGQUIT, it may also be ineffective.


When you need to stop a foreground process, try the following increasing order of force :

  1. Ctrl+C(SIGINT) : Attempt graceful termination.
  2. Ctrl+\(SIGQUIT) : Try a tougher interrupt and possibly get a core dump.
  3. Ctrl+Z(SIGTSTP) : Pause the process, then you can use kill -9 %job_idor (need to find the PID with or kill -9 <PID>first ). For background processes or processes with known PIDs:jobsps
  4. kill <PID>(SIGTERM) : Request a graceful exit.
  5. kill -QUIT <PID>(SIGQUIT) : A more forceful exit request, which may generate a core dump.
  6. 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 a tmuxsession, run commands within it, then detachclose your SSH connection or physical terminal, and attachreturn 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 pressing d. This simply disconnects your client (your current terminal) from tmuxthe server. tmuxThe server itself, along with all sessions, windows, panes, and processes it manages, continues to run in the background . detachNo signals are sent to tmuxprocesses running within it. You can reconnect using tmux attachor .tmux a
  • Close the pane/window (Exit/Kill):
    • In the Shell window of the pane, type exitor press Ctrl+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-paneor tmux kill-window.
    • Effect on processes: When a pane or window is closed, a signal tmux is normally sent to the foreground process group in that pane/window SIGHUP. This behavior is similar to closing a normal terminal. Therefore, if the foreground process in the pane has no handles SIGHUPor was not nohupstarted with , it will likely be terminated.

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 exitor Ctrl+D(close the pane): tmuxmay be python my_web_server.pysent to SIGHUP. If this Python server does not catch and handle SIGHUP(the default behavior is to terminate), then the server will stop .
  • 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 pane Ctrl+D: Even if tmuxsent SIGHUP, the service will continue to runnohup because the process was started with (ignored SIGHUP) or has been detached from the terminal (daemonized) . Closing this pane has no effect on it.

7.4. Sample code testing in tmux scenario

Let’s use the previous Python script tmuxto experiment in the environment:

  1. To start tmux: Type in your terminal tmux.
  2. 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).
  3. Test detachand attach:
    • tmuxRun in a pod (python simple_loop.py &run in the background, but nothing nohup). Note the PID.
    • detachSession (Ctrl+B d).
    • Go back to the normal terminal and check with ps aux | grep pythonor ps -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 then Ctrl+Cstop it, or use kill <PID>.
  4. Test closing the pane (simulating SIGHUP):
    • tmuxRun in a pane (python simple_loop.pyforeground, no signal handling, nothing nohup). Note the PID.
    • tmuxType in the pane exitor press to Ctrl+Dclose the pane.
    • Go back to the other terminal (tmuxor other pane/window of ) and check with ps aux | grep pythonor ps -p <PID>. Expected: The process has most likely terminated because it received SIGHUPand the default behavior is to exit.
  5. Test closing the pane (using nohup):
    • tmuxRun in the pod . nohup python simple_loop.py &Note the PID.
    • tmuxType in the pane exitor press to Ctrl+Dclose the pane.
    • Go back to the other terminal and check with ps aux | grep pythonor ps -p <PID>. Expected: The process is still running , but because it is nohupprotected by , it is ignored SIGHUP. The output will go to nohup.outthe file.
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide
Linux/Unix Signals Explained: Ctrl+C, Ctrl+Z, kill, pkill, nohup, &, and tmux Process Management Guide

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 SIGINTSIGTERMSIGKILLSIGHUP, 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)
  • Related Commands manManual Page Reference:
    • man 7 signal(Detailed signal description)
    • man 1 kill
    • man 1 pkill
    • man 1 nohup
    • man 1 tmux
    • man 2 signal(Programming interface)
    • man ps
    • man jobsman fg,man bg
END
 0
Comment(No Comments)