When running automated Bash scripts, cron jobs, network diagnostics, or CI/CD pipelines in Linux, external programs occasionally hang indefinitely. An uncooperative database connection, a stalled HTTP download, or an unresponsive remote SSH server can cause an entire deployment script to freeze forever, consuming system resources and preventing subsequent jobs from executing.
The GNU timeout command is an essential core utility designed specifically to enforce strict execution deadlines. It launches any specified command as a child process and automatically sends a termination signal if the process fails to complete within a designated timeframe. In this guide, we explore how to use the timeout command in the Linux terminal, configure custom signals, handle uncooperative processes with --kill-after, and evaluate exit codes.
In This Guide
- How the timeout Utility Works
- Basic Syntax and Duration Units
- Sending Custom Termination Signals (-s Option)
- Forcing Process Termination with –kill-after (-k Option)
- Evaluating Exit Statuses and Preserving Return Codes
- Managing Interactive and Foreground Processes
- Practical Automation and Scripting Examples
How the timeout Utility Works
When you prepend timeout to any command, it acts as an overseer process. It forks the target command and starts a high-precision internal timer. If the command finishes before the time limit expires, timeout exits cleanly and forwards the command’s original exit status code.
However, if the timer reaches zero before the target program finishes, timeout intercepts execution and sends a SIGTERM (Signal 15) to the child process, requesting an orderly shutdown. If the target process catches or ignores SIGTERM, timeout can escalate to an uncatchable SIGKILL (Signal 9).
Basic Syntax and Duration Units
The basic syntax for the timeout command is:
timeout [options] DURATION COMMAND [args...]
By default, if you specify an integer without a suffix, timeout interprets the duration in seconds:
timeout 10 ping 8.8.8.8
This command runs ping for exactly 10 seconds before terminating it.
You can also use explicit time unit suffixes:
s— Seconds (default): e.g.30sm— Minutes: e.g.5mh— Hours: e.g.2hd— Days: e.g.1d
For example, to limit a database backup script to a maximum run time of 2 hours:
timeout 2h ./backup_database.sh
Sending Custom Termination Signals (-s Option)
By default, timeout sends SIGTERM (Signal 15), allowing applications to flush memory buffers and close open file handles gracefully. However, some tools ignore SIGTERM or expect different signals—such as SIGINT (the equivalent of pressing Ctrl + C) or SIGHUP.
Use the -s (or --signal) flag followed by the signal name or number:
To send an interrupt signal (Ctrl + C):
timeout -s SIGINT 15s tcpdump -i eth0 -w capture.pcap
Because tcpdump flushes and finalizes packet captures cleanly upon receiving SIGINT, using -s SIGINT ensures the resulting .pcap file is not corrupted.
To view all available system signals supported by your Linux kernel, run:
kill -l
Forcing Process Termination with –kill-after (-k Option)
Occasionally, buggy programs, deadlocked threads, or processes stuck in uninterruptible kernel I/O sleep will catch or completely ignore SIGTERM, leaving the process frozen in memory indefinitely.
The -k (or --kill-after) option solves this by specifying a secondary grace period: if the initial signal fails to kill the process within that extra window, timeout sends a forceful, uncatchable SIGKILL (Signal 9):
timeout -k 10s 30s ./risky_worker_script.sh
In this example:
- The script runs normally up to 30 seconds.
- At 30 seconds,
timeoutissues an initialSIGTERM. - If the script does not shut down within the subsequent 10-second grace period,
timeoutforcefully obliterates the process withSIGKILLat the 40-second mark.
Evaluating Exit Statuses and Preserving Return Codes
When incorporating timeout into Bash logic, your script needs to know whether a command succeeded, failed normally, or exceeded its time limit:
- Exit Code 124: If the command times out and is terminated by
timeout, the exit status returned is124. - Exit Code 128 + N: If terminated by a signal N (for example, SIGKILL is 9, so 128 + 9 = 137).
You can evaluate this in shell scripts:
timeout 15s curl -s https://example.com/api/health
STATUS=$?
if [ $STATUS -eq 124 ]; then
echo "Alert: Health check timed out after 15 seconds!"
elif [ $STATUS -ne 0 ]; then
echo "Alert: Health check failed with error code $STATUS"
else
echo "Health check succeeded."
fi
If you want timeout to preserve the command’s native exit code rather than returning 124 upon timeout, add the --preserve-status flag.
Managing Interactive and Foreground Processes
When running commands directly from an interactive terminal session that require keyboard input or TTY access (such as text editors or interactive CLI menus), timeout normally runs commands in a separate process group. Adding --foreground allows the command to talk directly to the terminal TTY while maintaining the deadline:
timeout --foreground 60s read -p "Enter verification code: " CODE
Practical Automation and Scripting Examples
- Preventing Stalled SSH Connections:
Ensures batch deployment scripts do not freeze on offline remote nodes.timeout 10s ssh -o ConnectTimeout=5 user@remote_server "uptime" - Limiting Web Crawlers or Scrapers:
Caps documentation archiving jobs to half an hour.timeout 30m wget --mirror -p https://internal-docs.local - Diagnostic Connectivity Tests:
Quickly tests port reachability without waiting for standard operating system TCP timeout thresholds.timeout 5s nc -zv 192.168.1.50 443