Home / Alt manpages / time(1)

  • time(1)
  • User command
  • linux

Measure Commands with GNU time and Read the Result

You will finish with a repeatable way to measure a command, separate its output from the measurement, record a useful result, and interpret the exit status. The examples use GNU time 1.9-0.2build1 from the Debian time package installed on this machine.

Allow about ten minutes. You need a shell and a command you can run safely. The timing examples are ordinary user commands. The optional PAM configuration section changes access policy and needs root privileges.

1. Select the external command

Many shells provide a time keyword or builtin. Its output and options may differ from GNU time. Use the explicit path when you need the installed program documented by time(1):

$ command -v time
/usr/bin/time
$ /usr/bin/time --version
time (GNU Time) UNKNOWN
Copyright (C) 2018 Free Software Foundation, Inc.

The binary reports an unknown upstream version string, but the installed package is identifiable:

$ dpkg-query -W -f='${Package} ${Version}\n' time
time 1.9-0.2build1

Checkpoint: use /usr/bin/time in scripts and in troubleshooting notes when you need to remove any doubt about which implementation ran.

2. Run a harmless baseline measurement

Put every GNU time option before the command. Everything after the command name belongs to that command. The -p format gives portable real, user and system timings:

$ /usr/bin/time -p sh -c 'sleep 0.02'
real 0.02
user 0.00
sys 0.00

real is elapsed wall-clock time. user is CPU time spent running the command's code, and sys is CPU time spent in the kernel for it. The figures are measurements, not a promise that a command will take exactly the same time on the next run. Scheduling, caching and system load affect them.

GNU time writes its report to standard error by default. That is why the command's normal output can remain on standard output while the measurement is captured separately.

3. Choose a focused format

Use -f when the portable three-line result is too much or too little. The most useful starting specifiers are %E for elapsed time, %U for user CPU time, %S for system CPU time, %M for maximum resident memory in kilobytes, and %x for the command's exit status:

$ /usr/bin/time -f 'elapsed=%E user=%U sys=%S max-kb=%M exit=%x' sh -c 'printf "work\n"'
work
elapsed=0:00.00 user=0.00 sys=0.00 max-kb=... exit=0

The memory number and short timings vary by host, so treat the line above as a shape rather than a fixed transcript. If a format contains shell punctuation, quote it as one argument. A percent sign introduces a resource specifier; an unrecognised one is reported as a question mark followed by that character.

For a broad diagnostic report, use -v. It prints each available resource on its own line. Some resources are unavailable on some systems and can be reported as zero. Do not compare a single timing run with false precision, especially for commands that finish almost immediately.

4. Preserve the command's failure status

time normally returns the command's exit status. A non-zero command therefore remains visible to a script even though a timing report was produced:

$ /usr/bin/time -f 'exit=%x elapsed=%E' sh -c 'exit 7'
Command exited with non-zero status 7
exit=7 elapsed=0:00.00
$ printf 'status=%s\n' "$?"
status=7

The diagnostic wording and elapsed value can vary. The important checks are the non-zero shell status and the %x value. If the child is terminated by a signal, GNU time returns 128 plus the signal number, according to the installed manual. Avoid hiding that status with an unconditional || true while investigating a failure.

5. Write results to a file without losing them

Use -o FILE to write the report instead of standard error. It overwrites the destination by default. That is destructive to the old report, so choose a new filename or make a backup before using it:

$ /usr/bin/time -f 'elapsed=%E user=%U sys=%S' -o ./run-time.txt ./your-command --your-argument
$ sed -n '1p' ./run-time.txt
elapsed=0:00.05 user=0.01 sys=0.00

Replace the command and argument placeholders with real values. Do not paste an untrusted string as a shell command. To collect several runs, add -a, which appends instead of overwriting:

$ /usr/bin/time -a -f 'elapsed=%E' -o ./run-time.txt ./your-command --your-argument
$ wc -l ./run-time.txt
2 ./run-time.txt

Keep the output file outside a directory where another process can treat it as input. If the command fails halfway through a larger workflow, the timing line can still be useful, but it does not make partial command output safe or complete.

6. Keep the TIME environment setting in mind

If neither -f, -v nor -p is supplied, GNU time uses the TIME environment variable when it is set. That setting can make an apparently ordinary command produce unexpected output:

$ TIME='elapsed=%E user=%U sys=%S' /usr/bin/time true
elapsed=0:00.00 user=0.00 sys=0.00

For a reproducible command, pass the format explicitly or inspect the environment first:

$ printenv TIME
$ /usr/bin/time -p ./your-command

The command-line format wins over TIME. Avoid exporting a personal format in shell startup files if other people or scripts need predictable output.

7. Do not confuse time(1) with pam_time

The companion time.conf(5) manpage documents a different feature. It is the rule file for the PAM pam_time module, which can restrict a service for named users, terminals and times. It does not measure command performance, and running /usr/bin/time does not enforce these access rules.

Before changing policy, check whether the PAM service actually uses pam_time. This is a read-only inspection and may be run without root when the file is readable:

$ rg -n 'pam_time\.so' /etc/pam.d /etc/pam.conf
/etc/pam.d/login:...:account requisite pam_time.so

If the module is enabled, the rule file is /etc/security/time.conf. Each rule has four semicolon-separated fields: service, terminal, user and time. For example, a rule shaped like this matches the games service on any terminal, excludes user waster, and permits the listed out-of-hours periods:

games ; * ; !waster ; Wd0000-2400 | Wk1800-0800

The time field uses two-letter day tokens such as Mo, Wk, Wd and Al, followed by 24-hour start and finish times. A finish earlier than the start continues into the following day. Service, terminal and user lists can use !, & and |. All three of those fields must match for a rule to apply.

Policy warning: editing this file can lock users out of a PAM service. Back it up, edit it with sudoedit, and keep a root session open while testing. Restore the backup if access behaves unexpectedly:

$ sudo cp --preserve=mode,ownership,timestamps /etc/security/time.conf /etc/security/time.conf.backup
$ sudoedit /etc/security/time.conf
$ sudo cp --preserve=mode,ownership,timestamps /etc/security/time.conf.backup /etc/security/time.conf

The module logs badly formatted rules through syslog. It does not terminate an already-running session when its allowed time ends, so test the exact PAM service and keep an undo path before making a live change.

Done means

  • You used /usr/bin/time when GNU behaviour mattered and recorded the installed package version.
  • You can distinguish wall-clock, user CPU and system CPU time.
  • You know that the report goes to standard error and that the command's status is preserved.
  • You used -o deliberately, knowing it overwrites, and -a when collecting runs.
  • You checked the TIME environment variable when output was unexpected.
  • You kept performance measurement separate from the privileged, potentially disruptive pam_time policy file.