2012-09-26 34 views
6

Tôi đang chạy một chương trình trong Perl mà tại một thời điểm đánh giá dữ liệu trong câu lệnh if được gọi từ bên trong một chương trình con, ví dụ:Trong Perl có cách nào để khởi động lại chương trình hiện đang chạy từ bên trong chính nó không?

sub check_good { 
    if (!good) { 
     # exit this subroutine 
     # restart program 
    } 
    else { 
     # keep going 
    } 
} # end sub 

Sự cố tôi gặp phải khi thoát và khởi động lại. Tôi biết rằng tôi chỉ có thể sử dụng exit 0; để thoát ra ngay lập tức, nhưng rõ ràng điều này là không chính xác nếu tôi muốn quay lại phần đầu. Tôi đã thử gọi chương trình con mà về cơ bản bắt đầu chương trình, nhưng tất nhiên một khi nó đã chạy nó sẽ quay trở lại điểm này một lần nữa. Tôi nghĩ về việc đặt nó trong một vòng lặp while, nhưng điều này có nghĩa là đặt toàn bộ tập tin trong vòng lặp và nó sẽ rất không thực tế.

Tôi thực sự không biết liệu điều này có khả thi hay không, vì vậy mọi đầu vào đều tuyệt vời.

Trả lời

8

Nếu bạn chưa thay đổi @ARGV hoặc giữ bản sao của nó, bạn có thể làm điều gì đó như exec($^X, $0, @ARGV).

$^X and $0 (hoặc $EXECUTABLE_NAME$PROGRAM_NAME, xem nhận xét của Brian bên dưới) là trình thông dịch perl hiện tại và tập lệnh perl hiện tại tương ứng.

+0

tha thứ cho sự thiếu hiểu biết của tôi - Tôi biết @ARGV được sử dụng cho các đối số dòng lệnh, nhưng tôi đã sử dụng Tôi giả sử rằng họ lưu trữ dữ liệu trong cùng một vị trí bộ nhớ (hoặc một cái gì đó) ?. – dgBP

+0

Đó là một khẳng định bạn có thể dễ dàng kiểm tra. – DavidO

+0

Nếu bạn tiêu thụ stdin thì bạn sẽ phải tự đệm nó, có lẽ trong một tệp tạm thời. – tripleee

-1

Không có gì để ngăn bạn gọi system vào chính bạn. Một cái gì đó như thế này (rõ ràng cần một gọn gàng), nơi tôi vượt qua trong một đối số dòng lệnh để ngăn chặn các mã gọi chính nó mãi mãi.

#!/usr/bin/perl 
use strict; 
use warnings; 

print "Starting...\n"; 
sleep 5; 

if (! @ARGV) { 
     print "Start myself again...\n"; 
     system("./sleep.pl secondgo"); 
     print "...and die now\n"; 
     exit; 
} elsif ((@ARGV) && $ARGV[0] eq "secondgo") { 
     print "Just going to die straightaway this time\n"; 
     exit; 
} 
+0

Giải pháp này phụ thuộc vào tên tệp được cố định trước. Điều đó bắt đầu hút khi chúng tôi có nhiều liên kết hoặc liên kết tượng trưng trỏ đến tập lệnh này, dưới các tên khác nhau. Và đó vẫn là giả định rằng không có 'chdir' được thực hiện… Ngoài ra, bạn đang tạo ra một loạt các quá trình. Tự gọi mình một lần sẽ không thành vấn đề, nhưng hãy tự khởi động lại theo cách này 1000 lần có xu hướng lấp đầy bảng tiến trình và RAM. – amon

+0

Đồng ý với tất cả những điểm đó, tôi chỉ cố gắng chứng minh rằng bạn có thể tự khởi động lại. Các câu trả lời dưới đây và ở trên và rõ ràng hơn toàn diện. –

3

Cách khác là luôn có hai quy trình: Người giám sát và nhân viên.

Tái cấu trúc tất cả logic của bạn thành một chương trình con được gọi là run (hoặc main hoặc bất kỳ thứ gì). Nếu logic thực của bạn phát hiện ra rằng nó cần phải khởi động lại nó nên thoát ra với một mã thoát không được xác định trước (ví dụ như 1 ví dụ).

Sau đó, kịch bản chính của bạn và người giám sát sẽ trông như thế này:

if (my $worker = fork) { 
    # child process 
    run(@ARGV); 
    exit 0; 
} 
# supervisor process 
waitpid $worker; 
my $status = ($? >> 8); 

if ($status == 1) { ... restart .. } 

exit $status; # propagate exit code... 

Trong kịch bản đơn giản mà bạn chỉ muốn khởi động lại một lần, điều này có thể là một chút quá mức cần thiết. Nhưng nếu bạn ở bất kỳ thời điểm nào cần có khả năng xử lý các tình huống lỗi khác thì phương pháp này có thể thích hợp hơn.

Ví dụ: nếu mã thoát là 255, điều này cho biết rằng tập lệnh chính có tên die(). Trong trường hợp này, bạn có thể muốn triển khai một số quy trình quyết định để khởi động lại tập lệnh, bỏ qua lỗi hoặc báo cáo sự cố.

Có một vài mô-đun về CPAN triển khai những người giám sát như vậy. Proc::Launcher là một trong số đó và trang hướng dẫn bao gồm một cuộc thảo luận rộng rãi về các tác phẩm có liên quan. (Tôi chưa bao giờ sử dụng Proc :: Launcher, chủ yếu là do cuộc thảo luận này tôi liên kết với nó)

Các vấn đề liên quan