I've got a script that calls Perl's Time::HiRes module to calculate elapsed time. Basically the script gets the time by passing the following one-liner:
use Time::HiRes qw(time); print time
to the Perl interpreter via backticks and gets back the results.
#/bin/sh
START_TIME=`perl -e 'use Time::HiRes qw(time); print time'`
END_TIME=`perl -e 'use Time::HiRes qw(time); print time'`
ELAPSED_TIME=$(echo "($END_TIME - $START_TIME)" | bc)
echo $ELAPSED_TIME
I tried to rewrite it in a more modular way, but I'm stumped by the quoting rules of the Bash shell.
#/bin/sh
CALCULATE='bc'
NOW="perl -e 'use Time::HiRes qw(time); print time'"
START_TIME=`$NOW`
[Some long running task ...]
ELAPSED_TIME=$(echo "($NOW - $START_TIME)" | $CALCULATE)
echo $ELAPSED_TIME
Bash complains that something is not quoted properly. Why doesn't Bash just expand the command in $NOW and pass it to the backtick to be executed?
I tried various ways to embed Perl code in a shell script variable, but I can't seem to get it right.
How can I quote Perl code inside a shell script correctly?
Using a function is the most straightforward way to do this, I think:
#! /bin/bash
now() {
perl -e 'use Time::HiRes qw(time); print time';
}
calc=bc
time1=$(now)
time2=$(now)
elapsed=$(echo $time2 - $time1 | $calc)
echo $elapsed $time1 $time2
Essentially no quoting is required.
Your problem is that $NOW
is just a string with some Perl code in it. You need to tell Bash to execute it, with backticks or $()
:
ELAPSED_TIME=$(echo "($($NOW) - $START_TIME)" | $CALCULATE)
Also, Bash can do arithmetic natively:
ELAPSED_TIME=$(( $($NOW) - $START_TIME))
There isn't any need to invoke bc
.
Finally, starting and stopping perl
is likely to take a lot of time, which will add noise to your results. I'd recommend running perl
only once, and having perl
itself execute the long-running task. You'd then do all the computation within Perl itself as well:
#!/usr/bin/perl
use Time::HiRes qw(time);
my $start = time;
system(@ARGV);
my $end = time;
print "Elapsed: ", ($end - $start), "\n"
Or you could just use the Bash builtin time
(or /usr/bin/time
) to just do all the timing directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With