Как я могу выполнить код Perl, хранящийся внутри переменной сценария оболочки?
у меня есть скрипт, который вызывает модуль Perl Time::HiRes для вычисления прошедшего времени. В основном скрипт получает время, передавая следующую команду:
use Time::HiRes qw(time); print time
к интерпретатору Perl через задние тики и возвращает результаты.
#/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
Я попытался переписать его более модульным способом, но я озадачен правилами цитирования оболочки bash.
#/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 просто не расширить команда в $NOW и передать ее на задний ТИК для выполнения?
Я пробовал различные способы встраивания кода perl в переменную сценария оболочки, но не могу его получить право.
кто-нибудь знает, как правильно цитировать код perl внутри сценария оболочки?
5 ответов
использование функции-самый простой способ сделать это, я думаю:
#! /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
по существу не требуется цитирование.
ваша проблема в том, что $NOW
- это просто строка с некоторым кодом perl. Вы должны сказать bash, чтобы выполнить его, с помощью backticks или $()
:
ELAPSED_TIME=$(echo "($($NOW) - $START_TIME)" | $CALCULATE)
кроме того, bash может выполнять арифметику изначально:
ELAPSED_TIME=$(( $($NOW) - $START_TIME))
нет необходимости вызывать bc
.
наконец, запуск и остановка perl, вероятно, займет много времени, что добавит шума к вашим результатам. Я бы рекомендовал запускать perl только один раз, и сам perl выполняет длительную задачу. Тогда ты выполните все вычисления внутри самого perl:
#!/usr/bin/perl
use Time::HiRes qw(time);
my $start = time;
system(@ARGV);
my $end = time;
print "Elapsed: ", ($end - $start), "\n"
или вы можете просто использовать bash builtin time
(или /usr/bin/time
), чтобы просто сделать все время напрямую.
если $NOW
находится вне кавычек, он разбивается на пробелы.
$ perl -E'say 0+@ARGV; say for @ARGV' $NOW
7
perl
-e
'use
Time::HiRes
qw(time);
print
time'
вы можете окружить переменную двойными кавычками, чтобы избежать этого:
$ perl -E'say 0+@ARGV; say for @ARGV' "$NOW"
1
perl -e 'use Time::HiRes qw(time); print time'
но вы хотите выполнить эту строку как команду оболочки. Для этого используйте eval
.
$ eval "$NOW"
1335602750.57325
наконец, чтобы назначить его, мы используем backticks (или эквивалент $( ... )
).
$ START_TIME=$(eval "$NOW")
$ echo $START_TIME
1335602898.78472
ранее опубликованная функция, очевидно, чище, но вы сказали, что хотите помочь с цитирование.
кстати,
perl -e 'use Time::HiRes qw(time); print time'
можно сократить до
perl -MTime::HiRes=time -e'print time'
и даже до следующего (так как новая линия трейлинга отлично подходит):
perl -MTime::HiRes=time -E'say time'
или, если вы действительно хотели, чтобы гольф:
perl -MTime::HiRes=time -Esay+time
ниже приведена измененная версия вашего скрипта, вам в основном нужно понять, что некоторые приложения имеют стандартный вывод thiere в сторону stderr (Стандартная ошибка), поэтому, когда вы не видите, что их вывод помещен в переменную, вам просто нужно перенаправить его на stdout (стандартный вывод)
#/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
Я думаю, что использование преимущества времени найма отрицается тем фактом, что perl является относительно тяжелым внешним процессом, и он отдельно вызывается два раза. Если вам не нужно так много знаков после запятой для значения. вы можете использовать время, встроенное в bash, как
task() {
[Some long running task ...]
}
TIMEFORMAT=%R
elapse=$({ time task > task.out 2>&1; } 2>&1)
echo $elapse