715

I would like to display the completion time of a script.

What I currently do is -

#!/bin/bash
date  ## echo the date at start
# the script contents
date  ## echo the date at end

This just show's the time of start and end of the script. Would it be possible to display a fine grained output like processor time/ io time , etc?

mtk
  • 27,530
  • 35
  • 94
  • 130

20 Answers20

938

Just use time when you call the script:

time yourscript.sh
heemayl
  • 56,300
Trudbert
  • 9,549
  • 1
  • 14
  • 5
  • 144
    This outputs three times: real, user and sys. For the meanings of these, see here. – Garrett Jul 09 '15 at 01:56
  • 74
    and "real" is probably what people want to know - "Real is wall clock time - time from start to finish of the call" – Brad Parks Mar 29 '16 at 12:19
  • I think something like MATLAB timeit would be great here, because time itself will have a lot temporal fluctuations. – Léo Léopold Hertz 준영 Dec 25 '16 at 09:34
  • 12
    Is there a way to capture the stdout into a file? For example, something like time $( ... ) >> out.txt – Jon Apr 25 '18 at 18:18
  • 6
    You can also do this to sequences of commands on the command line, eg: time (command1 && command2) – meetar Apr 25 '18 at 20:30
  • 6
    Or he could, in his script, just do: echo $SECONDS assuming it is bash.... – Scott Prive Feb 22 '19 at 17:10
  • Another way to enter multiple commands: time sh -c "cat my.log | ggrep 'foo' | sort" – Anton Tarasenko Aug 08 '19 at 17:21
  • time doesn't show measurements in milliseconds and less though, so not useful for timing e.g. various solutions to code competitions. – Hi-Angel Mar 08 '20 at 14:20
  • 1
    Probably "real" time is the only time you're not interested in, @BradParks. The actual time the script takes to execute is user + sys time, as it also says in the link posted by Garrett. – NeilG Apr 02 '20 at 01:51
  • @NeilG - I just reviewed that link again, and it seems to me like real is what it says - clock time, which is what was asked, and what 99% of people want to know. – Brad Parks Apr 02 '20 at 10:39
  • 1
    @BradParks the OP specifically asks about "processor time /io time" not "just" the "start and end" time. The biggest concern everyone has is to eliminate the impact of other processes that might be running during the test and understand the script performance in more detail. Wall clock time will not do this. Garrett's link explains more fully. I'd be interested to know why you only want to know the wall clock time? – NeilG Apr 03 '20 at 01:26
  • I think the OP's question is asking 2 things - first, the clock time, then 2nd, additional details, like processor time/ io time , etc. And 99% of people looking here aren't looking for processor time, just total clock time a script took to run. But both are there, and your point and Garrent's are entirely accurate and helpful too – Brad Parks Apr 03 '20 at 01:32
  • 3
    @Jon: time, as a builtin, reads the rest of the command line, so any redirection would not work on its output. You need braces: {time myfunction} &> logs. – Michaël Dec 22 '20 at 22:27
  • time ./yourscript.sh – Anatolii Stepaniuk Jan 11 '21 at 07:43
  • @Michaël Great to know, thanks! However a semicolon and spaces around time are needed, i.e. { time myfunction } 2> logs (I also used 2> instead in order to only log the error stream, though { time myfunction } > >(tee log) 2>(tee err >&2) might also be interesting – Tobias Kienzler Jan 13 '21 at 11:06
  • @TobiasKienzler: The spaces and semicolon in braces are not needed in user-oriented shells, like ZSH. – Michaël Jan 13 '21 at 17:51
  • If you use sh, then it will be like this: time sh script.sh. – 7beggars_nnnnm Nov 02 '21 at 02:33
  • 2
    Note that the Bash built-in time is different from the command /usr/bin/time , the latter provides more detailed output. – Flimm Mar 04 '22 at 18:08
366

If time isn't an option,

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))

or, if you need sub-second precision and have bc installed,

start=`date +%s.%N`
stuff
end=`date +%s.%N`

runtime=$( echo "$end - $start" | bc -l )

Alex Meiburg
  • 133
  • 6
Rob Bos
  • 4,380
  • 42
    Note that this only works if you don't need sub-second precision. For some uses that might be acceptable, for others not. For slightly better precision (you're still invoking date twice, for example, so you might at best get millisecond precision in practice, and probably less), try using date +%s.%N. (%N is nanoseconds since the whole second.) – user Oct 19 '12 at 19:17
  • Good point. I thought of that just after leaving the keyboard but didn't come back. ^^ Also remember, OP, that "date" will itself add a few milliseconds to the run time. – Rob Bos Oct 20 '12 at 15:54
  • 2
    This is nice, but with the improvement from @MichaelKjörling I get the following error:bash: 1390472071.282341976: syntax error: invalid arithmetic operator (error token is ".282341976"), so maybe this needs more clarification. – Chris H Jan 23 '14 at 10:15
  • 5
    @ChrisH Oh. Good pointing it out; bash arithmetic expansion is integer-only. I see two obvious options; either ditch the period in the date format string (and treat the resultant value as nanoseconds since epoch), so use date +%s%N, or use something more capable like bc to calculate the actual runtime from the two values like jwchew suggests. Still, I feel this approach is a suboptimal way of doing it; time is considerably better if available, for reasons outlined above. – user Jan 23 '14 at 13:29
  • @MichaelKjörling, that explains it, I'm a bash novice so hadn't realised why. The nice ting about this approach is that it's easy to drop it in to an existing script and multiple (overlapping if necessary) timers can be used. I was using it to time a LaTeX compile process at around 20 seconds so 1 second precision was enough for me. Thanks for coming back to such an old thread so quickly! – Chris H Jan 23 '14 at 14:07
  • 12
    Just install bc and then do this: runtime=$( echo "$end - $start" | bc -l ) – redolent Feb 11 '15 at 22:01
  • 12
    If your script takes several Minutes, use: echo "Duration: $((($(date +%s)-$start)/60)) minutes – rubo77 Jul 29 '16 at 04:42
  • If you're on macOS you might need gdate installed (brew install coreutils) to get %N working. gdate +%s.%N – RaviU Mar 26 '19 at 23:44
  • 9
    Further to @rubo77 comment, if your script takes several hours use hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)" – Tom Nov 13 '19 at 15:24
  • Just FYI, on CentOS 6 I had to use start=$(date +%s) and end=$(date +%s), but otherwise works nicely. Added suggestions for hours/minutes by Tom and rubo77 to make it look nicer and easier to read as well. Thanks everyone! – LuxZg Jun 05 '23 at 12:01
109

Just call times without arguments upon exiting your script.

With ksh or zsh, you can also use time instead. With zsh, time will also give you the wall clock time in addition to the user and system CPU time.

To preserve the exit status of your script, you can make it:

ret=$?; times; exit "$ret"

Or you can also add a trap on EXIT:

trap times EXIT

That way, times will be called whenever the shell exits and the exit status will be preserved.

$ bash -c 'trap times EXIT; : {1..1000000}'
0m0.932s 0m0.028s
0m0.000s 0m0.000s
$ zsh -c 'trap time EXIT; : {1..1000000}'
shell  0.67s user 0.01s system 100% cpu 0.677 total
children  0.00s user 0.00s system 0% cpu 0.677 total

Also note that all of bash, ksh and zsh have a $SECONDS special variable that automatically gets incremented every second. In both zsh and ksh93, that variable can also be made floating point (with typeset -F SECONDS) to get more precision. This is only wall clock time, not CPU time.

  • 20
    That $SECONDS variable is very useful, thanks! – andybuckley Jun 18 '14 at 12:00
  • 1
    Does your approach eliminate the effect of temporal events? - - I think your approach is near time approach presented earlier. - - I think the timeit approach presented in MATLAB code can be useful here. – Léo Léopold Hertz 준영 Dec 25 '16 at 09:37
  • 4
    Hi, @Stéphane Chazelas. I found times doesn't give wall time, right? for example, bash -c 'trap times EXIT;sleep 2' – user15964 Jun 13 '17 at 02:17
  • Similar to https://unix.stackexchange.com/questions/269789/what-kind-of-times-does-times-output – akhan Sep 10 '18 at 02:24
  • Thanks for pointing out $SECONDS. The nice thing about it is that (at least in bash) you even can assign to it, which makes it reset to the value assigned, and counts up from then on. This makes calculations extremely easy, if not superfluous in most cases. Please note that I have no clue if other shells than bash behave the same way. – Binarus Dec 03 '20 at 09:19
  • 1
    @Binarus, yes, that feature comes from ksh. Contrary to ksh93/zsh, beside bash not supporting floating point, it's also broken in that after you set SECONDS to 0, it will change to 1 from 0 to 1 second later (as it only considers the result of time() which has only full second granularity). – Stéphane Chazelas Dec 03 '20 at 09:59
  • 1
    Thank you very much for the hint. So in bash it takes at least one second and at maximum two seconds until it changes to 1 after having set it to 0. However, I guess that this won't break anyone's scripts, because no reasonable person will use a measurement facility with 1s resolution to measure time spans of one or two seconds. I usually use it to check time spans of 30 seconds or more, and where it isn't important whether this is actually 31s or 29s ... But once again, thank you very much for bringing this subtle and very interesting difference between the various shells to our attention. – Binarus Dec 03 '20 at 11:07
  • 1
    @Binarus, not that's between 0 and 1. If you set SECONDS to 0 at 12:00:00.000, it will change to 1 one second later. But if you set it at 12:00:00.999, it will change to 1 one milisecond later. But yes, I agree it probably doesn't matter much in practice if you don't have sub-second precision anyway. – Stéphane Chazelas Dec 03 '20 at 11:18
  • I see. Then it's the other way around, which is not better and not worse. Thank you very much again! (I originally thought for some reason that the developers would have preferred delayed counting up over premature counting up, and have misunderstood your first comment about the subject). – Binarus Dec 03 '20 at 11:34
  • 1
    I find times useless in bash if command does mostly network-related IO. That doesn't need much of CPU, so times doesn't correlate with actual time that the command has taken – noonex Jun 26 '21 at 03:32
55

My method for bash:

# Reset BASH time counter
SECONDS=0
    # 
    # do stuff
    # 
ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
phk
  • 5,953
  • 7
  • 42
  • 71
Mark
  • 655
  • 2
    This does show elapsed time, but it doesn't show "fine grained output like processor time, I/O time" as requested in the question. – Chris Davies Jan 25 '17 at 22:10
  • 13
    Those searching for an answer to the question as posed are likely to find this solution useful. Your comment would be better addressed to the OPs question. – Mark Jan 26 '17 at 00:51
  • Why do you need to set SECONDS to 0 at the start? Reading up on this it sounds like it starts at 0 when the script starts. If you want to time the whole script could you safely skip that line? – sync Feb 21 '22 at 22:00
  • 1
    @sync Yes, if you are sure the script is actually run within its own subshell and does not inherit environment variables. It all depends. The safest way is local start=$SECONDS; … echo $((SECONDS-start)). – xebeche May 09 '22 at 23:34
  • Today I learned about $SECONDS : see https://askubuntu.com/questions/1028924/how-do-i-use-seconds-inside-a-bash-script. Could be useful to another bash newbie wondering why this would work – Théo Rubenach Jun 02 '23 at 14:35
43

I'm a bit late to the bandwagon, but wanted to post my solution (for sub-second precision) in case others happen to stumble upon this thread through searching. The output is in format of days, hours, minutes, and finally seconds:

res1=$(date +%s.%N)

do stuff in here

res2=$(date +%s.%N) dt=$(echo "$res2 - $res1" | bc) dd=$(echo "$dt/86400" | bc) dt2=$(echo "$dt-86400$dd" | bc) dh=$(echo "$dt2/3600" | bc) dt3=$(echo "$dt2-3600$dh" | bc) dm=$(echo "$dt3/60" | bc) ds=$(echo "$dt3-60*$dm" | bc)

LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

Hope someone out there finds this useful!

[edit] You need to count all characters in field definition in bash printf, if you want pad seconds to 2 digits before dot you have to define it as %07.4f (all digits and dot count too in to filed length) so the line should look like: LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%07.4f\n" $dd $dh $dm $ds

saper_2
  • 3
  • 2
jwchew
  • 555
  • 1
    I guess there is no other (only bash) way except using 'bc' to do the calculations. BTW really good script ;) – tvl Apr 18 '16 at 01:19
  • 1
    Beware that FreeBSD's date does not support sub-second precision and will just append literal “N” to the timestamp. – Anton Samsonov Jul 12 '16 at 09:25
  • 1
    Very nice script, but my bash doesn't handle the subsecond part. I also learned, that /1 in bc effectively strips that, so I added @/1@ to the $ds calculation, and it displays stuff very nice now! – Daniel Feb 01 '17 at 06:00
  • 1
    bc supports modulo: dt2=$(echo "$dt%86400" | bc). Just saying... BTW I prefer the form dt2=$(bc <<< "${dt}%86400") but that's entirely personal. – Dani_l Mar 07 '18 at 16:06
  • I don't know anything about bc yet, but the division by 86400 makes me mistrustful for the following reason: There are days which do not have 86400 seconds, for example days where time is switched from DST to normal time and vice versa, or days with leap seconds. If such days are part of the time span you want to calculate, i.e. are between res1 and res2 (including these values), your script will probably fail. – Binarus Dec 03 '20 at 11:15
  • This would be good answer if you rename the variable in a meaningful way. For example what is the res1 stands for. or dt, dd? it sounds like mathematical derivative. -1 for bad readability code. – MaXi32 Jun 20 '21 at 08:32
  • date +%s.%N doesn't seem to work on mac – mtk Feb 04 '22 at 04:23
30

Personally, I like to wrap all my script code in some "main" function like so:

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

Notice how easy is to use the time command in this scenario. Obviously you're not measuring the precise time including script parse time, but I find it accurate enough in most situations.

LeZuse
  • 401
  • 1
    Great solution, doesn't require extra tools and is self contained. – Cameron Wilby May 03 '20 at 22:05
  • 6
    This is the best solution. only problem is that you can't access script arguments from within main. To pass the arguments to the function you need to call time main "$@" in the last line – marmor Oct 07 '21 at 10:07
18

This question is quite old but in trying to find my favorite way of doing it this thread came up high... and I'm surprised no one mentioned it:

perf stat -r 10 -B sleep 1

'perf' is a performance analyzing tool included in the kernel under 'tools/perf' and often available to install as a separate package ('perf' in CentOS and 'linux-tools' on Debian/Ubuntu). The Linux Kernal perf Wiki has much more information about it.

Running 'perf stat' gives quite a bit of details including average execution time right at the end:

1.002248382 seconds time elapsed                   ( +-  0.01% )
zbateson
  • 281
  • 3
    What is perf? – B Layer Feb 20 '18 at 14:10
  • @B Layer - edited my answer to give a brief description of 'perf'. – zbateson Feb 21 '18 at 15:42
  • 1
    perf stat now complains about "You may not have permission to collect stats." unless you run some commands with sudo, which makes it useless in all scenarios where you don't completely own target machine. – alamar Nov 22 '18 at 13:30
  • Amazing, thanks! Way more fine-grained solution than time others suggesting. In particular, time is not applicable to measuring code competition solutions (as it doesn't print time in milliseconds and less), whereas your solution does. – Hi-Angel Mar 08 '20 at 14:25
11
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

Yes, this calls Python, but if you can live with that then this is quite a nice, terse solution.

Alex
  • 235
  • 6
    Beware that running that python command in a subshell and reading its output will take several millions of nanoseconds on most current systems. Same for running date. – Stéphane Chazelas Nov 22 '14 at 10:58
  • 15
    "Several millions of nanoseconds" is several milliseconds. People timing bash scripts are usually not very concerned about that (unless they run several billions of scripts per megasecond). – Zilk Jan 01 '16 at 03:34
  • 8
    Notice also that, even if the calculation is done inside a python process, the values were entirely collected before python was invoked. The execution time of the script will be measured correctly, without the "millions of nanoseconds" overhead. – Victor Schröder Feb 19 '19 at 10:07
  • time main above is so much more clean... yes, we can live with lots of degradation but it's way better without so let's stay engineers! – Michael Shigorin Jul 30 '20 at 18:11
  • $(echo $end - $start | bc) will do the same thing without python – James McGuigan Nov 16 '20 at 01:09
  • $( bc <<< "$end - $start" ) doesn't use a pipe, so it is marginally faster – Peter John Acklam Apr 24 '22 at 10:47
10

A small shell function that can be added before commands to measure their time:

#!/bin/bash

tm_date() { local start start=$(date +%s) "$@" local exit_code=$? echo >&2 "took ~$(($(date +%s) - start)) seconds. exited with ${exit_code}." return $exit_code }

tm_secs() { local start=$EPOCHSECONDS "$@" local exit_code=$? echo >&2 "took ~$((EPOCHSECONDS - start)) seconds. exited with ${exit_code}." return $exit_code }

tm_nanosecs() { local start=${EPOCHREALTIME/./} "$@" local exit_code=$? echo >&2 "took ~$((${EPOCHREALTIME/./} - start)) nanoseconds. exited with ${exit_code}." return $exit_code }

Then use it in your script, or on your command line like so:

tm the_original_command with all its parameters

For example,

tm_date sleep 1
tm_secs sleep 1
tm_nanosecs sleep 1

Will output,

took ~1 seconds. exited with 0.
took ~1 seconds. exited with 0.       
took ~1001608 nanoseconds. exited with 0.
8
  1. Just use time [any command]. Ex: time sleep 1 will sleep for a real time (ie: as timed by a stop watch) of ~1.000 to ~1.020 sec, as shown here:

     $ time sleep 1
    

    real 0m1.011s user 0m0.004s sys 0m0.000s

    What a beautiful thing. You can put any command after it, and it outputs the result in a nice, human-readable form. I really like to use it for timing builds. Ex:

     # time your "make" build
     time make
    

    time your "Bazel" build

    time bazel build //path/to/some:target

    ...or for git operations which can potentially be really long, so I can develop realistic mental expectations:

     # time how long it takes to pull from a massive repo when
     # I'm working from home during COVID-19. NB: `git pull`
     # is sooooo much slower than just pulling the one branch
     # you need with `git pull origin <branch>`, so just fetch
     # or pull what you need!
     time git pull origin master
    
  2. For more-customized timing needs where you may need to manipulate the output or convert it to other forms, in bash, use the internal $SECONDS variable. Here's a demo, including converting these seconds to other units, such as floating point minutes:

    Note that dt_min gets rounded from 0.01666666666... (1 second = that many minutes) to 0.017 in this case since I'm using the printf function to round. The sleep 1; part below is where you'd call your script to run and time, but I'm just sleeping for 1 second instead for the sake of this demo.

    Command:

     start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \
     dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \
     echo "dt_sec = $dt_sec; dt_min = $dt_min"
    

    Output:

     dt_sec = 1; dt_min = 0.017
    

Related:

  1. Read more about bc and printf in my answer here: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867
  2. I don't remember where I first learned about the time command anymore, but it may have been from @Trudbert's answer right here.
7

The accepted solution using time writes to stderr.
The solution using times writes to stdout.
The solutions using $SECONDS are missing sub-second precision.
The other solutions involve calling external programs like date or perf which is not efficient.
If you are fine with any of these, use it.

But if you need an efficient solution to get the times with millisecond precision and need them into variables such that the original output remains undisturbed you may combine process substitution with some redirections around time which is much faster than calling external programs and allows redirections around the timing wrapper script as on the original command/script.

# Preparations:
Cmd=vgs  # example of a program to be timed which is writing to stdout and stderr
Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }"  # other example; replace with your own
TIMEFORMAT="%3R %3U %3S"  # make time output easy to parse

Select one of the following variants parsing the output of time appropriate to you needs:
Shortest variant where stdout of $Cmd is written to stderr and nothing to stdout:

read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)

Longer variant that keeps original stdout and stderr separate of each other:

{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1

Most complicated variant includes closing the extra file descriptors such that $Cmd is called as if without this timing wrapper around it and lvm commands like vgs do not complain about leaked file descriptors:

{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1

You can even fake a floating point addition in bash without calling bc which would be much slower:

CPU=`printf %04d $((10#${User/.}+10#${System/.}))`  # replace with your own postprocessing
echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2  # redirected independent of $Cmd

Possible outputs with the two examples of $Cmd on a slow CPU:

File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
  VG   #PV #LV #SN Attr   VSize VFree
  b3     3  24   0 wz--n- 1.31t 1.19t
CPU 0.052 s, Elapsed 0.056 s

Or:

stdout
stderr
CPU 0.008 s, Elapsed 0.109 s
Juergen
  • 674
5
#!/bin/csh
#PBS -q glean
#PBS -l nodes=1:ppn=1
#PBS -l walltime=10:00:00
#PBS -o a.log
#PBS -e a.err
#PBS -V
#PBS -M shihcheng.guo@gmail.com
#PBS -m abe
#PBS -A k4zhang-group
START=$(date +%s)
for i in {1..1000000}
do
echo 1
done
END=$(date +%s)
DIFF=$(echo "$END - $START" | bc)
echo "It takes DIFF=$DIFF seconds to complete this task..."
  • 7
    How is this really different from the other answers already given which use date before and after the script and output the difference between them? – Eric Renouf Jan 15 '16 at 04:11
5

Use bash time builtin?

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:

TIMEFORMAT="The command took %Rs"
time {
    sleep 0.1
}

Output:

The command took 0.108s
brablc
  • 241
3

Using only bash it is also possible to measure and calculate the time duration for a portion of the shell script (or the elapsed time for the entire script):

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

you can now either just print the difference:

echo "duration: $((end-start)) seconds."

if you only need incremental duration do:

echo "duration: $((SECONDS-start)) seconds elapsed.."

You can also store the duration in a variable:

let diff=end-start
gauteh
  • 565
  • 1
    ^ THIS is the answer folks. Or more simply: $SECONDS at the end. It's a BUILT-IN Bash variable. All of the other answers are just doing extra work to re-invent this wheel... – Scott Prive Feb 22 '19 at 17:08
  • This is just a repetition of Marks earlier answer https://unix.stackexchange.com/a/340156/155362. – Juergen Aug 18 '20 at 01:29
3

Timing function based on SECONDS, limited to second-level granularity only, doesn't use any external commands:

time_it() {
  local start=$SECONDS ts ec
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Starting $*"
  "$@"; ec=$?
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Finished $*; elapsed = $((SECONDS-start)) seconds"
  # make sure to return the exit code of the command so that the caller can use it
  return "$ec"
}

For example:

time_it sleep 5

gives

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished
sleep 5; elapsed = 5 seconds
3

Another buildin solution (according to: https://stackoverflow.com/a/385422/1350091) is:

/usr/bin/time -v command
baziorek
  • 141
  • 1
  • 1
  • 6
  • time -v doesn't work, but /usr/bin/time -v does. – Artfaith Jun 08 '21 at 00:04
  • This may not be installed at the path you are suggesting to hardcode. To use the time binary, rather than the shell's built-in, the correct method to use is command time. If you have an external echo binary, similarly command echo Hello World would call this binary instead of using the built-in echo from the shell itself. Another method to avoid hardcoding paths would be "$(which echo)". To find out whether something is a shell built-in, use type: type time gives "time is a shell keyword"; type echo gives "echo is a shell builtin"; type sudo gives "sudo is /usr/bin/sudo" – Luc Feb 26 '23 at 15:56
2
#!/bin/bash
begin=$(date +"%s")

Script

termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Anthon
  • 79,293
1

Here's a variation of Alex's answer. I only care about minutes and seconds, but I also wanted it formatted differently. So I did this:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")
mpontillo
  • 314
1

An alternative if you want to measure multiple parts of a script:

#!/bin/bash
mts=$(date +%s%3N);mtl=$mts

sleep 1 mtc=$(date +%s%3N);printf "line $LINENO: %.3fs [+%.3fs]\n" "$((mtc - mts))e-3" "$((mtc - mtl))e-3";mtl=$mtc

sleep 1.5 mtc=$(date +%s%3N);printf "line $LINENO: %.3fs [+%.3fs]\n" "$((mtc - mts))e-3" "$((mtc - mtl))e-3";mtl=$mtc

output:

line 5: 1.007s [+1.007s]
line 8: 2.514s [+1.507s]

So it returns the total execution time and the time since the last measured line.

mgutt
  • 467
0

similar to @LeZuse's response but supports script arguments:

#!/bin/bash

main () { echo "my first argument is $1"

script content here

}

"$@" will expand to the script's arguments

time main "$@"

marmor
  • 241