4

空の角度演算子から読み取ると、プログラムにUNIXフィルターのセマンティクスが魔法のように与えられる、気の利いたperl機能を使用したいのですが、実際のファイルハンドル(またはIO :: Handleオブジェクトなど)<>を介してこの機能にアクセスできるようにしたいと思います。 、それをサブルーチンなどに渡すようなことができるようにします。これを行う方法はありますか?

「角度演算子」と「ファイルハンドル」を検索すると、角度演算子を使用してファイルハンドルから読み取る方法がわかるため、この質問をグーグルで検索するのは特に困難です。

4

3 に答える 3

9

差出人perldoc perlvar

  • ARGV

内のコマンドラインファイル名を反復処理する特別なファイルハンドル@ARGV。通常、角度演算子ではnullファイルハンドルとして記述されます<>。現在、オペレーターARGV内でのみ魔法の効果があることに注意してください。<>他の場所では、。によって開かれた最後のファイルに対応する単なるファイルハンドルです<>\*ARGV特に、ファイルハンドルを期待する関数にパラメーターとして渡すと、関数が内のすべてのファイルの内容を自動的に読み取らない場合があります@ARGV

私はそれがあなたの質問のすべての側面に「それを言うのは嫌いですが、それはあなたが望むことをしません」というような方法で答えると信じています。あなたができることは、開くファイル名のリストを受け取る関数を作成し、これを行うことです:

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

しかし、それはおそらくあなたが管理できる最高のものです。

于 2009-10-29T00:43:14.393 に答える
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]:さようなら
[file1:2]:こんにちは
[file1:3]:ありがとう
[file1:4]:翻訳なし
[file1:5]:
[file2:1]:chao
[file2:2]:hola
[file2:3]:gracias
[file2:4]:
于 2009-10-29T01:37:25.067 に答える
1

これはすでにとして実装されているようIterator::Diamondです。Iterator :: Diamondは、perlが。を読み取るときに使用する2引数のオープンマジックも無効にします<ARGV>。さらに良いことに'-'、他のすべての魔法を有効にすることなく、STDINとしての読み取りをサポートします。実際、私はそれをその目的のために単一のファイルだけで使用するかもしれません。

于 2010-04-26T04:50:34.193 に答える