How to Run Commands with a Time Limit in Linux Using the timeout Command

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.

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. 30s
  • m — Minutes: e.g. 5m
  • h — Hours: e.g. 2h
  • d — 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:

  1. The script runs normally up to 30 seconds.
  2. At 30 seconds, timeout issues an initial SIGTERM.
  3. If the script does not shut down within the subsequent 10-second grace period, timeout forcefully obliterates the process with SIGKILL at 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 is 124.
  • 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:
    timeout 10s ssh -o ConnectTimeout=5 user@remote_server "uptime"
    Ensures batch deployment scripts do not freeze on offline remote nodes.
  • Limiting Web Crawlers or Scrapers:
    timeout 30m wget --mirror -p https://internal-docs.local
    Caps documentation archiving jobs to half an hour.
  • Diagnostic Connectivity Tests:
    timeout 5s nc -zv 192.168.1.50 443
    Quickly tests port reachability without waiting for standard operating system TCP timeout thresholds.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.