timeout Command: Limiting Command Execution Time

timeout Command: Limiting Command Execution Time

What You'll Learn

  • How to limit how long a command runs with timeout
  • How to automatically stop a command that "hangs and never returns"
  • How to detect a timeout using exit status 124
  • How to force-kill a stubborn process that ignores SIGTERM with -k

Quick Summary (the patterns to remember first)

  • Run with a time limit → timeout 10 command (stops after 10 seconds)
  • Add a unit if you like → timeout 30s / timeout 5m / timeout 1h
  • Detect a timeout → exit status of 124 means it timed out
  • Still won't stop → timeout -k 5 10 command (force-kill after a grace period)

1. What Is the timeout Command?

Conclusion: timeout automatically ends a command once it exceeds a time limit you set. It's the go-to tool for preventing hangs.

Lina: Senpai, I ran a download command and it just never finished. The screen froze and I had to hit Ctrl+C. Is that the only way to stop it?
Linny-senpai: That's exactly where timeout helps. It lets you set a time limit: "run this command for at most N seconds, and stop it automatically if it goes over."
Lina: So I don't have to press Ctrl+C myself? It stops on its own?
Linny-senpai: Right. That prevents a command from being "stuck and left running." This matters especially for scripts that run automatically, or cron jobs — a hung command that sticks around causes real trouble. timeout is your safety net.

The basic idea of timeout

timeout 10 command
        ↑   ↑
        |   the command you want to run
        time limit (seconds)

"Finish within 10 seconds and it ends normally; go over and it's forcibly stopped."

2. Why Do You Need timeout?

Conclusion: A command that hangs on a network wait or an infinite loop can freeze your whole script. timeout prevents that.

Lina: But if a command works correctly, you don't really need a time limit, right?
Linny-senpai: Usually, no. The problem is commands where you don't know when they'll finish — connecting to an unresponsive server, pinging a host that's gone, or a loop you wrote wrong. Those can never return.
Lina: That's exactly what happened with my download...
Linny-senpai: If a human is watching, they can press Ctrl+C. But a cron job or automation script has nobody watching. The hung process lingers and the next step never starts. With timeout you set an upper bound, so at worst it "gives up after N seconds and moves on."

A hung command left alone can eat up memory or process slots, or cause overlapping cron runs. "Put a time limit on anything that might not finish" is the safe way to operate.

3. Basic Usage (Specifying the Time)

Conclusion: The form is timeout DURATION command. A bare number means seconds; add s/m/h/d for units.

The most basic form is:

$ timeout 10 sleep 30

sleep 30 normally waits 30 seconds. But with timeout 10, it's stopped after 10 seconds.

Lina: It ended in 10 seconds even though it was sleep 30! It stopped earlier than the promised 30 seconds.
Linny-senpai: Right, that's the time limit at work. A bare number means seconds. You can also add a unit to make it clearer.

You can attach a unit (suffix) to the duration.

$ timeout 30s command    # 30 seconds
$ timeout 5m command     # 5 minutes
$ timeout 1h command     # 1 hour
$ timeout 2d command     # 2 days

Duration units (suffixes)

Form Meaning
10 10 seconds (no unit = seconds)
30s 30 seconds
5m 5 minutes
1h 1 hour
2d 2 days

Decimals work too (timeout 0.5 command for 0.5 seconds).

4. Detecting Timeouts with Exit Status 124

Conclusion: When timeout cuts a command off, the exit status is 124. If echo $? shows 124, it timed out.

When timeout stops a command because the time ran out, the exit status becomes 124. Checking this lets you detect a timeout mechanically.

$ timeout 1 sleep 10
$ echo $?
124
Lina: The number 124 showed up. So that's the sign of a timeout.
Linny-senpai: Exactly. Conversely, if the command finishes normally within the time, its own exit status is returned — 0 for success, for example. So checking for 124 tells you whether it was "cut off partway through" or "finished properly."

If it finishes in time, the command's own status is returned.

$ timeout 10 sleep 1
$ echo $?
0

Exit statuses worth knowing

Value Meaning
124 Cut off by a timeout
125 The timeout command itself failed
126 Command found but could not run
127 Command not found
137 Force-killed by the KILL signal (-k) (128 + 9)

For now, just remember "124 = timed out."

5. Force-Killing Stubborn Processes with -k

Conclusion: timeout sends SIGTERM by default. If that's ignored, use -k DURATION to send SIGKILL after a grace period and stop it for sure.

Lina: I heard that sometimes a command won't stop even after timeout. Why is that?
Linny-senpai: Good question. When the time is up, timeout first sends a SIGTERM (a polite request to quit) to the command. But some programs ignore that request, so they don't stop.
Lina: So even when you ask it to "please stop," it won't listen... What do you do then?
Linny-senpai: That's when you use -k (kill-after). You set up a two-stage approach: "if it still hasn't stopped N seconds after the first request, force-kill it (SIGKILL)."
$ timeout -k 5 10 command

This means:

  • First, after 10 seconds, send SIGTERM (the polite request) to the command
  • If it still isn't stopped after another 5 seconds, send SIGKILL (force-kill)

How -k (kill-after) works

timeout -k 5 10 command
         ↑  ↑
         |  the real time limit (10s) → SIGTERM
         extra grace (5s) → SIGKILL if still running

A program cannot refuse SIGKILL. It's the last resort when you must stop it for sure.

SIGKILL (force-kill) stops the process without giving it a chance to clean up. A file being written may end up corrupted, so try a plain timeout (SIGTERM) first and use -k as a backup only when it won't stop.

6. Specifying the Signal (-s)

Conclusion: Use -s to change the signal sent. If you want the command's own status returned on timeout, use --preserve-status.

By default SIGTERM is sent, but you can specify a different signal with -s (--signal).

$ timeout -s SIGINT 10 command

This sends SIGINT, the same as Ctrl+C. Some commands shut down more gracefully with this than with SIGTERM.

Lina: Signals — those are things like SIGTERM and SIGKILL, right? There are different kinds?
Linny-senpai: Lots of them. The ones you use most with timeout are the polite SIGTERM (default), SIGINT (like Ctrl+C), and the last-resort SIGKILL. Signals themselves go a bit deep, so we'll cover them properly in another article (trap basics).

When you want the command's own exit status returned instead of 124 on timeout, use --preserve-status.

$ timeout --preserve-status 10 command

Use --preserve-status when you care about the value the command returned more than whether it timed out. Normally it's simpler to leave it off and check for 124.

7. Common Beginner Mistakes

Conclusion: It's easy to mix up the order of duration and command, the meaning of 124, and the argument order for -k.

7-1. Reversing the order of duration and command

# NG: the command comes first
$ timeout sleep 30 10

# OK: duration → command
$ timeout 10 sleep 30

A duration must always come right after timeout. Then write the command you want to run. Reverse the order and timeout errors out.

7-2. Mistaking 124 for an "error"

Lina: When 124 first appeared, I panicked and thought "the command broke!"
Linny-senpai: 124 is actually proof that timeout did its job on schedule. It's not a defect in the command — it means "it didn't finish in time, so I cut it off as planned." No need to panic.

7-3. Thinking you limited the whole pipeline when only part is limited

# This does not limit the whole pipeline
$ timeout 10 grep pattern file | sort

Only the timeout 10 grep pattern file part is limited; | sort is treated separately. To wrap an entire pipeline at once, use bash -c.

$ timeout 10 bash -c 'grep pattern file | sort'

8. Mini Exercises: Try It Yourself

Conclusion: Three tasks — cut off, check exit status, force-kill — to feel out timeout by hand.

Lina: I've got the concepts! I want to try it hands-on.
Linny-senpai: Great, I prepared three tasks. Using sleep makes it safe to experiment.

Task 1: Cut off sleep 30 after 3 seconds.

Show hint

The form is timeout DURATION command. A bare number means seconds.

Sample answer
$ timeout 3 sleep 30

Task 2: Right after Task 1, print the exit status and confirm it's 124 (timed out).

Show hint

The previous result is in $?.

Sample answer
$ timeout 3 sleep 30
$ echo $?

Seeing 124 means the timeout worked.

Task 3: Write a command that stops sleep 30 with "SIGTERM at 5 seconds, then SIGKILL if it's still running 2 seconds later."

Show hint

The order is -k GRACE LIMIT command.

Sample answer
$ timeout -k 2 5 sleep 30

9. Copy-Paste Templates

Conclusion: Keep the common patterns — basic, with units, detection, force-kill, pipeline — handy.

Common patterns to keep on hand

# Basic: stop after 10 seconds
timeout 10 command

# Add a unit (seconds / minutes)
timeout 30s command
timeout 5m command

# Detect a timeout (124 means timed out)
timeout 10 command
echo $?

# Force-kill if it won't stop (10s + 5s grace, then SIGKILL)
timeout -k 5 10 command

# Limit an entire pipeline
timeout 10 bash -c 'commandA | commandB'

# Stop with SIGINT (like Ctrl+C)
timeout -s SIGINT 10 command

Next Reading