464

I want to execute something in a linux shell under a few different conditions, and be able to output the execution time of each execution.

I know I could write a perl or python script that would do this, but is there a way I can do it in the shell? (which happens to be bash)

3

11 Answers 11

592

Use the built-in time keyword:

$ help time

time: time [-p] PIPELINE
    Execute PIPELINE and print a summary of the real time, user CPU time,
    and system CPU time spent executing PIPELINE when it terminates.
    The return status is the return status of PIPELINE.  The `-p' option
    prints the timing summary in a slightly different format.  This uses
    the value of the TIMEFORMAT variable as the output format.

Example:

$ time sleep 2
real    0m2.009s
user    0m0.000s
sys     0m0.004s
Sign up to request clarification or add additional context in comments.

6 Comments

How is this used on a command like time -p i=x; while read line; do x=x; done < /path/to/file.txt? It immediatly returns 0.00 unless I don't put anything before the while loop.. what gives?
this is poor 'time' version, bash builtin. where is external 'time' command?
@Znik, try /usr/bin/time
@natli: While time can time an entire pipeline as-is (by virtue of being a Bash keyword), you need to use a group command ({ ...; ...; }) to time multiple commands: time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
To see all versions of time you have installed on your system, you can use type -a time
|
140

You can get much more detailed information than the bash built-in time (i.e time(1), which Robert Gamble mentions). Normally this is /usr/bin/time.

Editor's note: To ensure that you're invoking the external utility time rather than your shell's time keyword, invoke it as /usr/bin/time. time is a POSIX-mandated utility, but the only option it is required to support is -p. Specific platforms implement specific, nonstandard extensions: -v works with GNU's time utility, as demonstrated below (the question is tagged ); the BSD/macOS implementation uses -l to produce similar output - see man 1 time.

Example of verbose output:

$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0

13 Comments

you wouldn't happen to know what debian package that would come from? doesn't seem to be installed by default
I was referencing your post Robert. Unless you mean the command you suggest is not the bash built-in?
Amazingly enough, it's installed from a package called "time".
The output from the /usr/bin/time looks like "0.00user 0.00system 0:02.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+172minor)pagefaults 0swaps"
@Nick: "sudo apt-get install time".
|
96
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"

2 Comments

There is much simpler way. Bash calculate automaticly special variable $SECONDS , then recalculation based on external date command is unneeded. $SECONDS variable keeps how many seconds bash script is running when it starts. This variable has some special property. See man page :D
I have tried both the above & the method in the comment. In the 1st I get an 'illegal variable' error & the 2nd I get 'unidentified variable'
51

For a line-by-line delta measurement, try gnomon.

$ npm install -g gnomon
$ <your command> | gnomon --medium=1.0 --high=4.0 --ignore-blank --real-time=100

A command line utility, a bit like moreutils's ts, to prepend timestamp information to the standard output of another command. Useful for long-running processes where you'd like a historical record of what's taking so long.

You can also use the --high and/or --medium options to specify a length threshold in seconds, over which gnomon will highlight the timestamp in red or yellow. And you can do a few other things, too.

example

1 Comment

Great tip, but just to be clear: this is useful for line-by-line timings, but the overhead of taking such fine-grained timings significantly adds to the overall timing.
25

Should you want more precision, use %N with date (and use bc for the diff, because $(()) only handles integers).

Here's how to do it:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Example:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Result:

Execution time: 0.104623 seconds

Comments

16

If you intend to use the times later to compute with, learn how to use the -f option of /usr/bin/time to output code that saves times. Here's some code I used recently to get and sort the execution times of a whole classful of students' programs:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

I later concatenated all the $timefile files and pipe the output into a Lua interpreter. You can do the same with Python or bash or whatever your favorite syntax is. I love this technique.

2 Comments

Note: The full path /usr/bin/time is necessary because although which time will tell you otherwise, if you simply run time, it will run your shell's version of time which does not accept any arguments.
I would go with env time :-)
15

If you only need precision to the second, you can use the builtin $SECONDS variable, which counts the number of seconds that the shell has been running.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done

1 Comment

Or just ... SECONDS=0; some_long_running_command; echo "This run took $SECONDS seconds" ..., cf. man bash
14

You can use time and subshell ():

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Or in same shell {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}

3 Comments

You posted two identical code snippets. You must have meant to have something different there.
@StasBekman is not true, first using ( & ) (new context, subshell), and other with { & } (same shell, same context)
Aha! I was looking really hard at the two and didn't see the difference. Thank you for clarifying that {} vs ().
2

The way is

$ > g++ -lpthread perform.c -o per
$ > time ./per

output is >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s

2 Comments

No need to use -lphtread or -o tags. Just need to use the time command, which the accepted answer explains better.
It was an example .That is my perform.c has threading so I need -lpthread and for simple identity it is -o per.
1

one possibly simple method ( that may not meet different users needs ) is the use of shell PROMPT.it is a simple solution that can be useful in some cases. You can use the bash prompting feature as in the example below:

export PS1='[\t \u@\h]\$' 

The above command will result in changing the shell prompt to :

[HH:MM:SS username@hostname]$ 

Each time you run a command (or hit enter) returning back to the shell prompt, the prompt will display current time.

notes:
1) beware that if you waited for sometime before you type your next command, then this time need to be considered, i.e the time displayed in the shell prompt is the timestamp when the shell prompt was displayed, not when you enter command. some users choose to hit Enter key to get a new prompt with a new timestamp before they are ready for the next command.
2) There are other available options and modifiers that can be used to change the bash prompt, refer to ( man bash ) for more details.

1 Comment

Not the point when program executes, but the duration of program executing.
1

perf stat Linux CLI utility

This tool is overkill for just getting time. But it can do so much more for you to help profile and fix slowness that it is worth knowing about. Ubuntu 22.04 setup:

sudo apt install linux-tools-common linux-tools-generic
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid

Usage:

perf stat <mycmd>

Sample run with stress-ng:

perf stat stress-ng --cpu 1 --cpu-method matrixprod -t 5

Sample output:

 Performance counter stats for 'stress-ng --cpu 1 --cpu-method matrixprod -t 5':

          5,005.46 msec task-clock                #    0.999 CPUs utilized          
                88      context-switches          #   17.581 /sec                   
                 1      cpu-migrations            #    0.200 /sec                   
             1,188      page-faults               #  237.341 /sec                   
    18,847,667,167      cycles                    #    3.765 GHz                    
    26,544,261,897      instructions              #    1.41  insn per cycle         
     3,239,655,001      branches                  #  647.225 M/sec                  
        25,393,369      branch-misses             #    0.78% of all branches        

       5.012218939 seconds time elapsed

       4.998051000 seconds user
       0.009122000 seconds sys

perf can also do a bunch more advanced things, e.g. here I show how to use it to profile code: How do I profile C++ code running on Linux?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.