opscape

Processes and jobs

timeout

Run a command with a time limit, and kill it if it is still running when the time is up.

timeout [OPTION...] DURATION COMMAND [ARG...]

11 of 11 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: timeout(1)

timeout 10 cmd runs cmd and, if it has not finished after 10 seconds, sends it TERM. It is the simplest way to stop a script from hanging forever on a network call, a lock or a test that never returns. Durations take a suffix: s (the default), m, h or d, and fractions are allowed (0.5, 1.5m).

The exit status tells you what happened. If the command finished in time, timeout returns the command's own status. If it was killed, timeout returns 124. 125 means timeout itself failed, 126 the command could not be run, 127 it was not found. With -s KILL the status is 137 instead of 124 (128 + 9). Checking for 124 is how a script tells "too slow" from "failed".

Programs that catch or ignore TERM can outlive the limit; -k DURATION sends KILL that long after the first signal, which nothing can ignore. When the command is a shell script with children, timeout signals the whole group it started, so the children are stopped too.

Examples

Limit how long a command may run

timeout 1 sleep 5
echo "exit status: $?"
output
exit status: 124

sleep 5 is killed after one second. The exit status 124 is timeout's way of saying "the time ran out", distinct from any status the command itself returns.

A command that finishes in time keeps its own status

timeout 5 ls README.md missing.txt
echo "exit status: $?"
output
ls: cannot access 'missing.txt': No such file or directory
README.md
exit status: 2

ls finished well within the limit, so its own exit status (2, a file was missing) passes straight through.

Tell a timeout from a failure in a script

timeout 2 curl -s http://localhost:8080/api/status.json > status.json
rc=$?
if [ "$rc" -eq 124 ]; then echo "timed out"
elif [ "$rc" -ne 0 ]; then echo "failed with $rc"
else echo "ok: $(wc -c < status.json) bytes"; fi
output
ok: 56 bytes

Save $? right away, then branch on it: 124 means slow, anything else non-zero means the command itself failed. Here the local test server answered at once.

Use minutes, hours and fractions

timeout 0.5 sleep 10; echo "0.5 s: $?"
timeout 1m sleep 0.1; echo "1 minute: $?"
output
0.5 s: 124
1 minute: 0

0.5 is half a second and 1m a minute (h and d work too). The second sleep ends long before its limit, so the status is sleep's own 0.

Report when the limit is hit

timeout -v 1 sleep 5
echo "exit status: $?"
output
timeout: sending signal TERM to command ‘sleep’
exit status: 124

-v (--verbose) prints a line on standard error naming the signal sent, which makes timeouts visible in CI and cron logs.

Kill a command that ignores TERM

timeout -k 1 1 bash -c 'trap "" TERM; while :; do sleep 0.1; done'
echo "exit status: $?"
output
/bin/bash: line 1:  3422 Killed                  timeout -k 1 1 bash -c 'trap "" TERM; while :; do sleep 0.1; done'
exit status: 137

The child ignores TERM (and so does every sleep it starts), so the first signal does nothing. -k 1 sends KILL one second later. timeout delivers it to the whole process group it runs in, itself included, so bash reports timeout as Killed and the status is 137 (128 + 9) rather than 124.

Send a different signal

timeout -s INT 1 bash -c 'trap "echo caught INT, saving work; exit 3" INT; sleep 5 & wait'
echo "exit status: $?"
output
caught INT, saving work
exit status: 124

-s INT sends what Ctrl-C would, which some programs handle more gracefully than TERM. The child cleans up and exits 3, but because the time ran out, timeout still reports 124.

Return the command's status even on timeout

timeout --preserve-status 1 sleep 5
echo "exit status: $?"
output
exit status: 143

--preserve-status returns whatever the command exited with, here 143 (killed by TERM), instead of 124. Useful when a caller only understands the command's own codes.

Give a command a deadline for reading input

sleep 2 | timeout 0.5 cat
echo "exit status: ${PIPESTATUS[1]}"
output
exit status: 124

cat waits for input that is not coming. timeout gives up after half a second; PIPESTATUS[1] holds the status of the second command of the pipeline. For prompts in your own scripts, read -t is simpler.

Exit codes for a command that cannot run

timeout 5 no-such-command
echo "not found: $?"
timeout 5 ./README.md
echo "not executable: $?"
timeout 5x sleep 1
echo "bad duration: $?"
output
timeout: failed to run command ‘no-such-command’: No such file or directory
not found: 127
timeout: failed to run command ‘./README.md’: Permission denied
not executable: 126
timeout: invalid time interval ‘5x’
Try 'timeout --help' for more information.
bad duration: 125

127 means the command does not exist, 126 that it exists but cannot be executed, and 125 that timeout itself rejected its arguments, here the unknown unit x.

Time-limit a shell function

slow() { sleep 5; echo "never"; }
export -f slow
timeout 1 bash -c slow
echo "exit status: $?"
output
exit status: 124

timeout runs programs, not shell functions. Export the function with export -f and run it in a child bash, which timeout can then limit.

Common pitfalls

  • Treating every non-zero status as "timed out". Only 124 (or 137 with -s KILL) means the limit was hit; other codes come from the command.

  • Putting options after the duration: timeout 10 -s KILL cmd runs a program called -s. Options go first: timeout -s KILL 10 cmd.

  • Using timeout on something interactive from a script. timeout puts the command in the background from the terminal's point of view, so it cannot read the keyboard; --foreground allows it, at the cost of not timing out the command's children.

  • Assuming TERM is enough. A process that ignores it keeps running; pair the limit with -k (timeout -k 5 60 cmd) when it must end.

  • Wrapping a function, alias or builtin: timeout 5 myfunc fails with status 127. Run bash -c around it.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • timeout is from GNU coreutils. macOS does not ship it; Homebrew's coreutils installs it as gtimeout. FreeBSD has its own timeout with the same basic usage and the 124 convention.

Options worth knowing

A selection, described in our own words. For the full list, see timeout(1) or timeout --help.

OptionWhat it does
-s, --signal SIGNALSend SIGNAL (a name such as INT or a number) on timeout instead of TERM.
-k, --kill-after DURATIONIf the command is still running DURATION after the first signal, send KILL.
-p, --preserve-statusExit with the command's status even when it timed out.
-v, --verbosePrint a message on standard error when a signal is sent.
-f, --foregroundLet the command use the terminal; its children are then not timed out.

Related