2012-04-28 34 views
6

Tôi có một tập lệnh gọi mô-đun Thời gian :: HiRes của Perl để tính thời gian trôi qua. Về cơ bản các kịch bản được thời gian bằng cách đi qua sau một liner:Làm cách nào để thực thi mã Perl được lưu trữ bên trong biến tập lệnh shell?

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

để thông dịch Perl qua ve lưng và nhận lại kết quả.

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

Tôi đã cố gắng viết lại theo cách mô đun hơn nhưng tôi bị bối rối bởi các quy tắc trích dẫn của 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 phàn nàn rằng nội dung nào đó không được trích dẫn đúng cách. Tại sao không bash chỉ mở rộng lệnh bằng $ NOW và chuyển nó vào dấu tick để thực thi?

Tôi đã thử nhiều cách khác nhau để nhúng mã perl trong biến tập lệnh shell nhưng dường như không thể nhận được mã này .

Bất kỳ ai biết cách trích dẫn mã perl bên trong tập lệnh trình bao chính xác?

+0

@Mat Để giúp mọi người dễ dàng trả lời hơn, tôi chỉ trích đoạn trích từ tập lệnh lớn hơn nhiều. Tôi cắt và dán nó sai. Cảm ơn bạn đã chỉ ra. Đã sửa. Nhưng vấn đề vẫn là trích dẫn mặc dù. – GeneQ

+1

FYI, bạn có thể viết perl của bạn một lớp lót như 'perl -MTime :: HiRes = time -e 'in time'' –

Trả lời

7

Sử dụng một hàm là cách đơn giản nhất để làm điều này, tôi nghĩ rằng:

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

Về cơ bản không có trích dẫn yêu cầu.

+0

Đó là nó! Tôi ngớ ngẩn quá. Nói về việc bị kẹt trong một cái hộp. Đôi khi tôi quên rằng Bash là một ngôn ngữ lập trình đầy đủ. Cảm ơn. – GeneQ

3

Vấn đề của bạn là $NOW chỉ là một chuỗi có một số mã perl trong đó. Bạn cần phải cho bash để thực hiện nó, với backticks hoặc $():

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

Ngoài ra, bash có thể làm phép tính nguyên bản:

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

Không cần phải gọi bc.

Cuối cùng, bắt đầu và dừng perl có thể mất nhiều thời gian, điều này sẽ làm tăng thêm tiếng ồn cho kết quả của bạn. Tôi muốn khuyên bạn nên chạy perl chỉ một lần, và có perl chính nó thực hiện nhiệm vụ chạy dài. Sau đó bạn sẽ làm tất cả những tính toán trong bản thân perl cũng như:

#!/usr/bin/perl 

use Time::HiRes qw(time); 

my $start = time; 
system(@ARGV); 
my $end = time; 

print "Elapsed: ", ($end - $start), "\n" 

Hoặc bạn chỉ có thể sử dụng bash BUILTIN time (hoặc /usr/bin/time) để chỉ làm tất cả những thời gian trực tiếp.

+0

Điểm tốt về thời gian tải thông dịch perl. Nhưng đó là một số mã cũ tôi đang duy trì vì vậy tôi không muốn thay đổi nó quá nhiều. Chuyển sang Perl sẽ chuyển nó, không phải tái cấu trúc và đó là một chút quá nhiều công việc. Tôi muốn viết nó trong Perl tinh khiết bất kỳ ngày nào. – GeneQ

+4

"không cần phải gọi bc" - bash của tôi (và 'expr') không làm arithmetics với số thập phân. – Mat

+0

@Mat, ah, vâng, zsh đã làm, điều đó đã ném tôi ra một chút ở đó – bdonlan

1

Nếu $NOW nằm ngoài dấu ngoặc kép, nó được chia thành khoảng trắng.

$ perl -E'say [email protected]; say for @ARGV' $NOW 
7 
perl 
-e 
'use 
Time::HiRes 
qw(time); 
print 
time' 

Bạn có thể bao quanh biến bởi hai dấu ngoặc kép để tránh điều này:

$ perl -E'say [email protected]; say for @ARGV' "$NOW" 
1 
perl -e 'use Time::HiRes qw(time); print time' 

Nhưng bạn muốn thực hiện rằng chuỗi như một lệnh shell. Để làm điều đó, hãy sử dụng eval.

$ eval "$NOW" 
1335602750.57325 

Cuối cùng, để gán, chúng tôi sử dụng các dấu gạch chéo (hoặc tương đương $(...)).

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

Chức năng được đăng trước đây rõ ràng là sạch hơn, nhưng bạn nói bạn muốn được trợ giúp trích dẫn.


Bằng cách này,

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

có thể được rút ngắn xuống còn

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

và thậm chí cả những điều sau đây (kể từ khi dòng mới trailing là hoàn toàn tốt đẹp):

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

Hoặc nếu bạn thực sự muốn gol f:

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

Đã thêm một chút vào cuối màu. – ikegami

0

dưới đây là một phiên bản sửa đổi của kịch bản của bạn, về cơ bản bạn cần phải hiểu rằng một số ứng dụng có thiere đầu ra tiêu chuẩn đối với stderr (sai số chuẩn) nên khi bạn không nhìn thấy đầu ra của họ đưa vào một biến bạn chỉ cần chuyển hướng nó vào stdout (outputp tiêu chuẩn)

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

tôi nghĩ rằng việc sử dụng lợi ích của thuê thời gian được phủ nhận bởi thực tế là perl là một quá trình bên ngoài tương đối nặng và nó được gọi riêng hai lần. Nếu bạn không cần nhiều vị trí thập phân cho giá trị đó. bạn có thể sử dụng thời gian dựng sẵn trong bash như

task() { 
    [Some long running task ...] 
} 
TIMEFORMAT=%R 
elapse=$({ time task > task.out 2>&1; } 2>&1) 
echo $elapse 
Các vấn đề liên quan