2009-10-29 2 views
4

빈 각도 연산자 <>을 읽는 것이 마술처럼 프로그램의 UNIX 필터 의미를 알려주고 있지만 실제 파일 핸들 (IO::Handle 개체 또는 유사)을 통해이 기능에 액세스 할 수 있기를 원한다면 멋있는 perl 기능을 사용하고 싶습니다. 그래서 서브 루틴 등으로 전달하는 것과 같은 일을 할 수 있습니다. 이 일을 할 수있는 방법이 있습니까?실제 파일 핸들에서 Perl의 빈 각도 "<>"연산자에 액세스 하시겠습니까?

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

+0

당신이 찾고있는 <>의 행동이 명확하지 않습니다. 내가 아는 한, <>와 <$filehandle>의 유일한 차이점은 <>가 주어진 경우 파일 이름 인수 (@ARGV)로 대체된다는 것입니다. 이게 네가 말하는거야? – dlowe

+0

나는'<>'파일 핸들을 함수에 전달하려고한다고 생각한다. –

+0

아아, 이제 알겠습니다. 나는 그 질문을 거꾸로 읽었다 ... – dlowe

답변

9

:

  • ARGV

특수 파일 핸들이 @ARGV에서 명령 줄 파일 이름을 반복. 일반적으로 앵글 연산자 <>에 null 파일 핸들로 기록됩니다. 현재 ARGV<> 연산자 내에서만 마법 효과가 있습니다. 다른 곳에서는 <>에 의해 열린 마지막 파일에 해당하는 일반 파일 핸들입니다. 특히 \*ARGV을 매개 변수로 전달하여 파일 핸들이 필요한 함수에 전달하면 함수가 @ARGV에있는 모든 파일의 내용을 자동으로 읽지는 않습니다.

저는 "네가 싫어하지만 네가 원하는대로 할 수 없다"라는 질문에 모든 답변을한다고 믿습니다. 당신이 할 수있는 것은 열려면 파일 이름의 목록을 기능을하고,이 작업을 수행 할 수 있습니다 :

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

을하지만 그것은 아마 당신이 관리 할 수 ​​있습니다 최고입니다.

+0

물론 다른 파일명을 필요로하는 클래스를 만드는 또 다른 대답을 잊어 버렸고'<> '연산자가'@> ARGV'와 같은 방식으로 그것들을 읽도록 오버로드했습니다. 그것은 심지어 약간의 확장 가능성을 가지고 있습니다. –

+1

'<>'에 대한 좋은 점은 파일 이름이 없으면'STDIN'에서 읽는 것입니다. –

+0

그래, 우리는 잠재적으로 그것을 잃을 것이다 (최소한 추가하는 것은 어색 할 것이다). 그러나 우리는 그것을 전달하는 능력을 얻게 될 것이다. –

6

크리스 루츠의 생각을 확장, 여기에 아주 초보적인 구현 :로 사용할 수 있습니다

#!/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]: 
+3

Awww ... [자신의 구현의 시작을 부끄러워 보인다.] –

+2

문자열 해석의 오버로드가 현재 파일 이름을 인쇄하는 것을 정말 좋아합니다. 그건 정말 영리합니다. –

+1

@Chris Lutz : 고마워요. 드디어 과부하를 통해 현재의 회선 번호에 액세스하는 방법을 알아 냈습니다. 재미있는 것들. –

1

그것은 다음과 같습니다 이미 Iterator::Diamond으로 구현되었습니다. Iterator :: Diamond는 perl이 <ARGV>을 읽을 때 사용하는 2 인자 공개 매직을 비활성화합니다. 더 좋은 점은 다른 마법을 모두 사용하지 않고 '-'을 STDIN으로 읽는 것을 지원한다는 것입니다. 실제로, 나는 그것을 단일 파일에 대해서만 사용할 수 있습니다.

관련 문제