| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | bash 5.2.26-6.el10time 1.9-25.el10coreutils 9.5-8.el10_2 |
| Applies to | Linux distributions with Bash installed |
| Privilege | Normal user |
| Scope | Measure Bash script and command execution time with the time reserved word, $SECONDS, $EPOCHREALTIME, and date +%s; compare Bash time to GNU /usr/bin/time; save timing output to a file. Includes a short timeout example only; signal handling and advanced timeout options are out of scope. |
| Related guides | Bash background process Bash best practices Shell scripting course hub |
To check how long a Bash script takes, run it under the shell's time reserved word:
time ./myscript.shIf the file is executable and has a shebang, that is enough. Otherwise call Bash explicitly:
time bash ./myscript.shSample output:
done
real 0m2.015s
user 0m0.012s
sys 0m0.002sreal is the total elapsed time from start to finish. user and sys are CPU time in user mode and kernel mode.
When a script waits on disk or network, real is often much larger than user plus sys. On parallel or multi-process work, user plus sys can exceed real because CPU time adds up across cores and child processes—see run shell scripts in parallel for overlapping & jobs timed with the same TIMEFORMAT pattern.
Bash Execution Time Methods Compared
| Method | Precision | Best for |
|---|---|---|
Bash time reserved word |
Subsecond | Time an entire command, pipeline, or script from the shell |
$SECONDS |
Whole seconds | Measure phases inside a Bash script |
$EPOCHREALTIME |
Microsecond-granularity timestamp | Subsecond elapsed timing in Bash 5+ |
date +%s |
Whole seconds | Classic shell timestamp difference |
/usr/bin/time (GNU Time) |
Subsecond plus resource stats | CPU, memory, and I/O investigation |
time, $SECONDS, and $EPOCHREALTIME measure elapsed time. GNU timeout (from coreutils) solves a different problem: stopping a command that runs too long.
Measure a Bash Script with time
Bash provides time as a reserved word so it can time pipelines, builtins, and shell functions. It is not the same program as /usr/bin/time.
For example:
time sleep 1Sample output:
real 0m1.005s
user 0m0.004s
sys 0m0.000sBash writes the timing summary to stderr after the timed command finishes. Because time is shell syntax, it can time pipelines, brace groups, and shell functions that GNU /usr/bin/time cannot see directly.
Format Bash time Output with TIMEFORMAT
For POSIX-style output, Bash also accepts time -p:
time -p sleep 1Sample output:
real 1.01
user 0.00
sys 0.00-p uses Bash's POSIX timing format instead of the format specified by TIMEFORMAT.
Set TIMEFORMAT before you use the Bash time keyword for a custom layout. This variable does not affect /usr/bin/time:
TIMEFORMAT='real %3R sec (user %3U sys %3S)'
time sleep 1Sample output:
real 1.006 sec (user 0.003 sys 0.001)%R is real seconds, %U is user CPU, and %S is sys CPU. Run help TIMEFORMAT in Bash for the full format list.
Time Pipelines, Functions, and Command Groups
Brace groups run as one timed unit:
time { sleep 0.5; echo done; }Sample output:
done
real 0m0.506s
user 0m0.004s
sys 0m0.001sA pipeline is timed as a whole:
time echo hello | wc -cSample output:
6
real 0m0.006s
user 0m0.005s
sys 0m0.001sTo time a shell function, call it in the same shell where time runs. GNU /usr/bin/time cannot do that unless you wrap the call in bash -c or export the function to a subshell.
Save Bash time Output to a File
Bash writes its timing summary to stderr, not stdout. Group the timed command so a stderr redirect catches the timing report:
{ time ./myscript.sh; } 2> timing.logThe braces group the timed command so the 2> redirection also applies to Bash's timing report. That redirect captures stderr from the script too. If ./myscript.sh prints echo "ERROR" >&2, timing.log contains that line as well as the real / user / sys summary. When you need timing statistics in their own file, GNU /usr/bin/time -o is simpler.
On RHEL, GNU Time comes from the time package, not coreutils:
/usr/bin/time -o gnu-timing.log -f '%e' sleep 1The command's own stdout and stderr stay on the terminal; only the formatted stats go to the file. Read them with:
cat gnu-timing.logSample output:
1.00With the Bash group redirect, read the mixed stderr log like this:
cat timing.logSample output:
real 0m2.021s
user 0m0.009s
sys 0m0.005sBash time vs /usr/bin/time
type -a time on a typical Linux host shows both the keyword and the external program:
type -a timeSample output:
time is a shell keyword
time is /usr/bin/timeBash runs its keyword when you write time cmd in an interactive shell or script. To force GNU Time, call it by path:
/usr/bin/time -f 'real %e user %U sys %S maxrss %M KB' sleep 1Sample output:
real 1.00 user 0.00 sys 0.00 maxrss 1892 KBInstall GNU Time separately on RHEL if /usr/bin/time is missing. Package
installs use dnf command:
sudo dnf install time| Feature | Bash time |
GNU /usr/bin/time |
|---|---|---|
| Directly time a pipeline | Yes | No; wrap it in bash -c '...' |
| Directly time a shell function | Yes | No; requires another shell or export |
| Resource and memory statistics | Limited | Yes with -f or -v |
| Format output | TIMEFORMAT |
-f |
| Write stats to a file | Redirect stderr (2>) |
-o / --output |
Use Bash time for shell-heavy work. Use GNU Time when you also need memory or I/O statistics.
Measure Elapsed Time Inside a Script with SECONDS
Bash's SECONDS variable reports the number of seconds since the shell started. Assigning a value resets the reference point, so SECONDS=0 is convenient for elapsed-time measurement:
SECONDS=0
sleep 2
echo "SECONDS=$SECONDS"Sample output:
SECONDS=2The value is an integer. You get whole seconds only, which is enough for coarse phase timing in maintenance scripts.
You can reset SECONDS before each stage of a script:
SECONDS=0
echo "backup start"
sleep 1
echo "backup phase took ${SECONDS}s"Sample output:
backup start
backup phase took 1sTo print hours, minutes, and seconds, divide the elapsed value:
SECONDS=0
sleep 65
duration=$SECONDS
printf 'Elapsed: %02d:%02d:%02d\n' \
$((duration / 3600)) \
$(((duration % 3600) / 60)) \
$((duration % 60))Sample output:
Elapsed: 00:01:05Reassign SECONDS=0 before each phase when you want per-step durations in one script. The variable is per shell instance; subshells inherit but do not share updates back to the parent.
Measure Subsecond Time with EPOCHREALTIME
Bash 5.0 and later expose EPOCHREALTIME as seconds since the Unix epoch with a fractional part at microsecond granularity. Shell arithmetic is integer-only, so subtract start and end in awk for a decimal elapsed time:
start=$EPOCHREALTIME
sleep 0.2
awk -v s="$start" -v e="$EPOCHREALTIME" 'BEGIN {printf "%.3f\n", e-s}'Sample output:
0.206The awk command handles the floating-point subtraction Bash cannot do in $(( )). bc can perform the same subtraction if your script already depends on it.
To print the elapsed time whenever the shell exits, register an EXIT trap:
start=$EPOCHREALTIME
report_duration() {
awk -v s="$start" -v e="$EPOCHREALTIME" 'BEGIN {printf "Elapsed: %.2fs\n", e-s}' >&2
}
trap report_duration EXIT
sleep 1
echo "work done"Sample output:
work done
Elapsed: 1.01sThe EXIT trap runs when the shell exits, so the elapsed-time message still prints when the script finishes with a non-zero status. See Bash trap for other EXIT-trap patterns.
Measure Elapsed Time with date +%s
Another common approach is to record Unix timestamps before and after a command:
start=$(date +%s)
sleep 2
end=$(date +%s)
echo $((end - start))Sample output:
2This pattern works in shells where the installed date utility supports %s. On Bash, $SECONDS is usually simpler because you do not need two variables and a subtraction.
GNU date +%s%N prints epoch seconds followed by the nanosecond field, which can be used for subsecond timing. BSD date and POSIX sh do not guarantee %N. Treat %N as a GNU/Linux shortcut, not a portable standard.
Accuracy and Portability Notes
$SECONDSis Bash-specific and reports whole seconds only.$EPOCHREALTIMEneeds Bash 5+ and follows the system wall clock. NTP steps can make a delta look odd; the timestamp has microsecond granularity, not guaranteed microsecond measurement accuracy.date +%sis widely available for second-level deltas;%Nis not portable.- Use wall-clock timing for script logs and troubleshooting; pair timing with trace debugging in Debug a Bash script when elapsed time alone does not explain a hang. Use a dedicated benchmark tool (
hyperfine,perf, or a language-specific harness) for performance comparisons.
Limit Script Execution Time with timeout
timeout does not measure execution time; it stops a command after a specified duration. For wall-clock loops, EPOCHSECONDS, and exit 124 handling in more depth, see Bash while loop until a deadline:
timeout 30s ./myscript.shWith the default settings, GNU timeout sends SIGTERM when the duration expires and returns status 124 for a timeout:
timeout 5s sleep 10
echo "exit=$?"Sample output:
exit=124Summary
Check Bash script execution time from the shell with time ./script.sh or time bash script.sh. Read real for wall-clock elapsed time; user and sys show CPU usage, which can be lower or higher than real depending on I/O waits and parallelism.
Inside a script, $SECONDS gives integer elapsed seconds, which you can convert to HH:MM:SS. $EPOCHREALTIME with awk supports subsecond elapsed timing on Bash 5 and later. date +%s remains a widely supported second-level timestamp pattern. GNU /usr/bin/time from the time package adds resource statistics and -o for log files; Bash time stays inside the shell and handles pipelines and functions directly.
Use these methods for script logging and troubleshooting. Use a dedicated benchmark tool when comparing performance. To enforce a maximum runtime instead of measuring elapsed time, use timeout 30s ./script.sh, which exits 124 when the limit is hit.
References
- Bash Reference Manual — Pipelines (
time) - Bash Reference Manual — Bash Variables (
TIMEFORMAT,SECONDS,EPOCHREALTIME) - GNU Time manual
- GNU coreutils —
timeoutinvocation
Frequently Asked Questions
How do I check how long a Bash script takes to run?
Run time ./script.sh when the file is executable, or time bash ./script.sh otherwise. The real line on stderr is elapsed wall-clock time.
What do real, user, and sys mean in Bash time output?
real is wall-clock elapsed time from start to finish. user is CPU time in user mode and sys is CPU time in kernel mode. I/O waits inflate real; parallel work can make user plus sys exceed real.
How do I measure milliseconds in a Bash script?
On Bash 5+, read $EPOCHREALTIME at the start and end, then subtract in awk because shell arithmetic is integer-only. date +%s%N works on many GNU/Linux systems but is not portable to BSD or POSIX sh.
How do I save Bash time output to a variable or file?
Bash writes timing to stderr. { time ./script.sh; } 2> timing.log saves the timing report, but the same redirect also captures stderr from the script. GNU /usr/bin/time -o file writes statistics to a separate file without mixing script output.
What is the difference between Bash time and /usr/bin/time?
Bash time is a reserved word that can time pipelines, builtins, and shell functions in the current shell. /usr/bin/time is GNU Time, a separate program that reports resource statistics but must wrap shell syntax in bash -c when needed.

