How can I execute Perl code stored inside a shell variable of a script?

I have a script that calls the Perl Time :: HiRes module to calculate elapsed time. Basically the script gets time by passing the following single-line:

use Time::HiRes qw(time); print time 

to the Perl interpreter via reverse ticks and returns 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 was surpassed by the citation 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 being quoted incorrectly. Why doesn't bash just expand the command into $ NOW and pass it to the back tick that will be executed?

I tried various ways to embed perl code in a script shell variable, but didn't seem to be able to get it correctly.

Does anyone know how to correctly specify perl code inside a shell script?

+6
source share
5 answers

Using a function is the easiest 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 citation needed.

+7
source

Your problem is that $NOW is just a line with some perl code. You should tell bash to execute it with reverse windows or $() :

 ELAPSED_TIME=$(echo "($($NOW) - $START_TIME)" | $CALCULATE) 

Additionally, bash can do arithmetic natively:

 ELAPSED_TIME=$(( $($NOW) - $START_TIME)) 

No need to call bc .

Finally, starting and stopping perl will probably take a long time, which will add noise to your results. I would recommend running perl only once and perl itself to perform a long-term task. Then you performed all the calculations inside perl itself:

 #!/usr/bin/perl use Time::HiRes qw(time); my $start = time; system(@ARGV); my $end = time; print "Elapsed: ", ($end - $start), "\n" 

Or you can just use bash builtin time (or /usr/bin/time ) to just execute all the time.

+3
source

If $NOW is out of quotation marks, it becomes space-separated.

 $ perl -E'say 0+@ARGV ; say for @ARGV' $NOW 7 perl -e 'use Time::HiRes qw(time); print time' 

You can surround the variable with double quotes to avoid this:

 $ perl -E'say 0+@ARGV ; say for @ARGV' "$NOW" 1 perl -e 'use Time::HiRes qw(time); print time' 

But you want to execute this line as a shell command. Use eval for this.

 $ eval "$NOW" 1335602750.57325 

Finally, to assign it, we use the return outputs (or the equivalent of $( ... ) ).

 $ START_TIME=$(eval "$NOW") $ echo $START_TIME 1335602898.78472 

The previously published feature is clearly cleaner, but you said you want help with quoting.


By the way

 perl -e 'use Time::HiRes qw(time); print time' 

can be reduced to

 perl -MTime::HiRes=time -e'print time' 

and even to the following (since the final newline fits perfectly):

 perl -MTime::HiRes=time -E'say time' 

Or if you really wanted to play golf:

 perl -MTime::HiRes=time -Esay+time 
+1
source

below is a modified version of your script, you basically need to understand that some applications have standard output for stderr (standard error), so when you don’t see that their output is placed in a variable, you just need to redirect it to standard output ( standard output)

 #/bin/sh CALCULATE='bc' echo 'starting' NOW=$(perl -e 'use Time::HiRes qw(time); print time' 2>&1) sleep 3 echo 'ending' END_TIME=$(perl -e 'use Time::HiRes qw(time); print time' 2>&1) ELAPSED_TIME=$(echo "($NOW - $START_TIME)") echo $ELAPSED_TIME 
0
source

I think that taking advantage of HiRes time is negated by the fact that perl is a relatively heavy external process and it is called separately twice. Unless you need so many decimal places for the value. you can use bash built-in time like

 task() { [Some long running task ...] } TIMEFORMAT=%R elapse=$({ time task > task.out 2>&1; } 2>&1) echo $elapse 
0
source

Source: https://habr.com/ru/post/914405/


All Articles