문제

나는 빈 앵글 연산자의 독서가있는 Nifty Perl 기능을 사용하고 싶습니다. <> 마술처럼 프로그램 UNIX 필터 의미론을 제공하지만 실제 파일 핸들 (또는 io :: 핸들 객체 또는 이와 유사한), 서브 루틴 등으로 전달하는 것과 같은 일을 할 수 있습니다. 이것을 할 방법이 있습니까?

"앵글 연산자"와 "파일 핸들"을 검색하면 앵글 연산자를 사용하여 파일 핸들에서 읽는 방법을 알려주기 때문에이 질문은 특히 Google이 어렵습니다.

도움이 되었습니까?

해결책

에서 perldoc perlvar:

  • ARGV

명령 줄 파일 이름을 반복하는 특수 파일 핸들 @ARGV. 일반적으로 각도 연산자의 NULL 파일 핸들로 작성되었습니다. <>. 현재 주목하십시오 ARGV 내에서만 마법 효과가 있습니다 <> 운영자; 다른 곳에서는 열린 마지막 파일에 해당하는 일반 파일 핸들입니다. <>. 특히 통과 \*ARGV 파일 핸들을 기대하는 함수의 매개 변수로서 기능이 모든 파일의 내용을 자동으로 읽지 않을 수 있습니다. @ARGV.

나는 당신의 질문의 모든 측면에 "그것을 말하기를 싫어하지만 당신이 원하는 것을 할 수는 없다"고 생각합니다. 당신이 할 수있는 일은 파일 이름 목록을 열고 다음을 수행하는 기능을 만드는 것입니다.

sub takes_filenames (@) {
  local @ARGV = @_;
  // do stuff with <>
}

그러나 그것은 아마도 당신이 관리 할 수있는 최고 일 것입니다.

다른 팁

Chris Lutz의 아이디어를 확장하면서 매우 기본적인 구현이 있습니다.

#!/usr/bin/perl

package My::ARGV::Reader;

use strict; use warnings;
use autodie;
use IO::Handle;

use overload
    '<>' => \&reader,
    '""' => \&argv,
    '0+' => \&input_line_number,
;

sub new {
    my $class = shift;
    my $self = {
        names => [ @_ ],
        handles => [],
        current_file => 0,
    };
    bless $self => $class;
}

sub reader {
    my $self = shift;

    return scalar <STDIN> unless @{ $self->{names}};

    my $line;

    while ( 1 ) {
        my $current = $self->{current_file};
        return if $current >= @{ $self->{names} };

        my $fh = $self->{handles}->[$current];

        unless ( $fh ) {
            $self->{handles}->[$current] = $fh = $self->open_file;
        }

        if( eof $fh ) {
            close $fh;
            $self->{current_file} = $current + 1;
            next;
        }

        $line = <$fh>;
        last;
    }
    return $line;
}

sub open_file {
    my $self = shift;
    my $name = $self->{names}->[ $self->{current_file} ];
    open my $fh, '<', $name;
    return $fh;
}

sub argv {
    my $self = shift;
    my $name = @{$self->{names}}
             ? $self->{names}->[ $self->{current_file} ]
             : '-'
             ;
    return $name;
}

sub input_line_number {
    my $self = shift;
    my $fh = @{$self->{names}}
           ? $self->{handles}->[$self->{current_file}]
           : \*STDIN
           ;
    return $fh->input_line_number;
}

다음과 같이 사용할 수 있습니다.

package main;

use strict; use warnings;

my $it = My::ARGV::Reader->new(@ARGV);

echo($it);

sub echo {
    my ($it) = @_;
    printf "[%s:%d]:%s", $it, +$it, $_ while <$it>;
}

산출:

[file1:1]:bye bye
[file1:2]:hello
[file1:3]:thank you
[file1:4]:no translation
[file1:5]:
[file2:1]:chao
[file2:2]:hola
[file2:3]:gracias
[file2:4]:

이것은 이미 구현 된 것 같습니다 Iterator::Diamond. 반복자 :: 다이아몬드는 또한 판독 할 때 Perl이 사용하는 2- 연락 마법을 비활성화합니다. <ARGV>. 더 좋은 점은 독서를 지원합니다 '-' Stdin으로서 다른 모든 마법을 가능하게하지 않습니다. 사실, 나는 단일 파일에서만 그 목적으로 사용할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top