2012-03-19 31 views
10

Hãy xem xét kịch bản vô nghĩa sau đây là một ví dụ:Ngăn chặn perl từ in thông điệp cảnh báo giống hệt

use strict; 
use warnings; 

my $uninitialisedValue; 

while(<>){ 
    print ${$uninitialisedValue}{$_},"\n"; 
} 

nào được chạy từ dòng lệnh:

$ perl warningPrinter.pl < longfile.txt 

Bất kể những gì STDIN chứa, các STDOUT sẽ có đầy đủ:

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 1. 

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 2. 

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 3. 

Use of uninitialized value in print at warningPrinter.pl line 16, <> line 4. 
... 

Tôi làm việc với các tệp rất dài, vì vậy nhận được kết quả này khi xuất hiện ting kịch bản của tôi là ít nhất là kích thích nhẹ. Có thể mất một lúc để quy trình phản hồi tín hiệu chấm dứt CTRL-c và thiết bị đầu cuối của tôi đột nhiên được điền cùng thông báo lỗi.

Có cách nào nhận được perl để in chỉ là trường hợp đầu tiên của một thông điệp cảnh báo giống hệt nhau và tái xuất hiện hay chỉ làm cho thông điệp cảnh báo gây tử vong cho việc thực thi tập lệnh? Thấy như tôi chưa bao giờ sản xuất một kịch bản hoạt động mặc dù có cảnh báo trong họ, tôi cũng chấp nhận. Nhưng nó có lẽ thuận tiện hơn nếu tôi có thể nhận được perl để in cảnh báo giống hệt nhau chỉ một lần.

+4

Hãy thử bài này StackOverflow khác: [Làm thế nào tôi có thể làm cho Perl chết nếu một cảnh báo được tạo ra?] [1] [1]: http://stackoverflow.com/questions/3896060/how- can-i-make-perl-die-if-a-cảnh báo-được tạo ra –

+1

Tuyệt vời. 'sử dụng cảnh báo FATAL => 'all'' hoạt động rất tốt để giết chết quá trình này sau một cảnh báo trong trường hợp của tôi. – MattLBeck

+1

Không sử dụng 'for' khi đọc tệp, đặc biệt khi tệp đó lớn, vì vòng lặp for sẽ tải trước danh sách của nó vào bộ nhớ. Sử dụng 'while' để thay thế. Ngoài ra, chuyển hướng một tập tin để stdin là dư thừa, chỉ cần sử dụng các tập tin như là đối số. Trong vấn đề cụ thể của bạn, mở lại STDERR cho một tập tin có thể là một giải pháp. – TLP

Trả lời

10

Tôi nghĩ mình sẽ chỉ cho bạn cách tạo ra cảnh báo logic duy nhất. Tôi không khuyên bạn nên nó mặc dù:

my %printed; 
local $SIG{__WARN__} = sub { 
    my $message = shift; 
    my ($msg, $loc) = $message =~ m/(.*?) at (.*?line \d+)/; 
    print $message unless $printed{$loc}{$msg}++; 
}; 

tôi nên nói rằng tôi không khuyên bạn nên điều này như một thói quen chung. Bởi vì tốt hơn là nên có chính sách cảnh báo. Đó là một thao tác có thể có giá trị không xác định hoặc bạn không muốn xử lý giá trị undef. Tôi cố gắng xóa tất cả các cảnh báo khỏi mã đã hoàn thành của mình.

Trong trường hợp đầu tiên, đặt no warnings 'uninitialized'; vào vòng lặp for dễ hơn nhiều - và thường xuyên điều cần làm. Trong trường hợp thứ hai, bạn có thể muốn thất bại. Tuy nhiên, nếu đó là điều bạn thực sự muốn xử lý nhưng cảnh báo một lần, hãy nói rằng bạn muốn xử lý dữ liệu mạnh mẽ, nhưng muốn cảnh báo các quy trình ngược dòng mà bạn có một số dữ liệu xấu, bạn có thể tạo một sub warn_once:

{ use Carp(); 
    my %warned; 
    sub warn_once { 
     my $message = shift; 
     my ($msg, $loc) = $message =~ m/(.*?) at (.*?line \d+)/; 
     Carp::carp($message) unless $warned{$loc}{$msg}++; 
    }; 
} 

Và gọi nó là như thế này:

while (<>) { 
    warn_once('$uninitialisedValue is uninitialized') 
     unless defined($uninitialisedValue) 
     ; 
    no warnings 'uninitialized'; 
    print ${$uninitialisedValue}{$_},"\n"; 
} 

Sau đó, bạn đã quyết định điều gì đó.

+0

Tuyệt vời! Tôi đoán tôi sẽ phải thêm loại điều này vào mọi kịch bản mà tôi muốn sử dụng logic này? Tại sao bạn không nên giới thiệu nó? – MattLBeck

+0

@kikumbob Tôi sẽ xây dựng trong bài viết của mình. – Axeman

+2

Lưu ý rằng mô-đun 'chẩn đoán' thực hiện tất cả điều này ngoại trừ phần về xem xét số dòng của đoạn đầu vào. – tchrist

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