6

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 は、何かが適切に引用されていないと文句を言います。Bash が $NOW でコマンドを展開し、それをバッククォートに渡して実行しないのはなぜですか?

シェル スクリプト変数に Perl コードを埋め込むさまざまな方法を試しましたが、うまくいきません。

シェルスクリプト内の Perl コードを正しく引用するにはどうすればよいですか?

4

5 に答える 5

7

関数を使用することは、これを行うための最も簡単な方法だと思います:

#! /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

基本的に引用は不要です。

于 2012-04-28T08:37:49.587 に答える
3

問題は、それ$NOWが Perl コードを含む単なる文字列であることです。バッククォートまたは を使用して、Bash に実行するように指示する必要があります$()

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 ビルトインtime(または/usr/bin/time) を使用して、すべてのタイミングを直接行うこともできます。

于 2012-04-28T08:40:49.020 に答える
1

引用符の外にある場合$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

最後に、それを割り当てるために、バッククォート (または同等のもの$( ... )) を使用します。

$ 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
于 2012-04-28T08:46:31.317 に答える
1

以下は、スクリプトの修正版です。基本的に、一部のアプリケーションでは標準出力が標準エラー (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
于 2012-04-28T09:19:40.437 に答える
0

perlHiRes 時間の利点は、比較的重い外部プロセスであり、別々に 2 回呼び出されるという事実によって打ち消されると思います。

値の小数点以下の桁数がそれほど必要ない場合。次のようにBashに組み込まれている時間を使用できます

task() {
    [Some long running task ...]
}
TIMEFORMAT=%R
elapse=$({ time task > task.out 2>&1; } 2>&1)
echo $elapse
于 2012-05-08T08:27:25.367 に答える