84

I wish to find out how long an operation takes in a Linux shell script. How can I do this?

codeforester
  • 39,467
  • 16
  • 112
  • 140
yazz.com
  • 57,320
  • 66
  • 234
  • 385

6 Answers6

129

Using the time command, as others have suggested, is a good idea.

Another option is to use the magic built-in variable $SECONDS, which contains the number of seconds since the script started executing. You can say:

START_TIME=$SECONDS
dosomething
ELAPSED_TIME=$(($SECONDS - $START_TIME))

I think this is bash-specific, but since you're on Linux, I assume you're using bash.

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • 5
    The only caveat I'd add here is that using all-caps names for your own variables is bad form, since it means you can overwrite shell-builtin variables by mistake (f/e, if someone assigns to `SECONDS`, it stops having its special meaning). See POSIX spec @ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, reserving lowercase for application use, keeping in mind that shell and environment variables share a single namespace -- *The name space of environment variable names containing lowercase letters is reserved for applications.* – Charles Duffy Mar 14 '19 at 20:18
42

Use the time command. time ls /bin.

Keith
  • 42,110
  • 11
  • 57
  • 76
40

Try following example:

START_TIME=$SECONDS
# do something
sleep 65

ELAPSED_TIME=$(($SECONDS - $START_TIME))

echo "$(($ELAPSED_TIME/60)) min $(($ELAPSED_TIME%60)) sec"    
#> 1 min 5 sec
16

Many of the answers mention $SECONDS, but that variable is actually even better than they realize:

Assignment to this variable resets the count to the value assigned, and the expanded value becomes the value assigned plus the number of seconds since the assignment.

This means you can simply query this variable directly at the end of your script to print the elapsed time:

#!/usr/bin/env bash

# Do stuff...

echo "Script finished in $SECONDS seconds."

You can also time smaller sections like so:

#!/usr/bin/env bash

# Do stuff

SECONDS=0

# Do timed stuff...

echo "Timed stuff finished in $SECONDS seconds."
Tammer Saleh
  • 393
  • 4
  • 7
6

Here is the script to find the time elapsed in milliseconds. Replace the sleep 60 line with the code you want to execute.

a=0
while [ $a -lt 10 ]
do
    START_TIME=`echo $(($(date +%s%N)/1000000))`
    sleep 3
    END_TIME=`echo $(($(date +%s%N)/1000000))`
    ELAPSED_TIME=$(($END_TIME - $START_TIME))
    echo $ELAPSED_TIME
    if [ $a -eq 10 ]
    then
        break
    fi
    a=`expr $a + 1`
done
codeforester
  • 39,467
  • 16
  • 112
  • 140
user3300239
  • 75
  • 2
  • 6
1

GNU time

I'm also a big fun of the GNU time command: https://www.gnu.org/software/time/ which offers some important options compared to the time Bash built-in.

Sample usage:

env time --format '%e' --output time.log sleep 1

Output:

1.00

Explanation:

  • env: to find /usr/bin/time instead of the Bash built-in

  • --format '%e': print time in seconds, see man time.

    This is often what I want when benchmarking: a single number rather than minutes + seconds.

And an important pattern I often use is:

bench-cmd() (
  logfile=time.log
  echo "cmd $@" >> "$logfile"
  printf 'time ' >> "$logfile"
  bench_cmd="env time --append --format '%e' --output '$logfile' $@"
  eval "$bench_cmd"
  echo >> "$logfile"
)

rm -f time.log
bench-cmd sleep 1
bench-cmd sleep 2
bench-cmd sleep 3
cat time.log

GitHub upstream.

Output:

cmd sleep 1
time 1.00

cmd sleep 2
time 2.00

cmd sleep 3
time 3.00

Explanation:

  • --output: output the time to a file.

    By default, the output goes to stderr, so this option is important to separate the timing from the stderr of the command.

  • --append: append to the file instead of overwriting.

    This allows me to concentrate the entire benchmark output in a single file.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985