実際のファイルハンドルからPerlの空の角度「<>」演算子にアクセスしますか?
-
08-07-2019 - |
質問
空の角度演算子<>
を読み取ると、プログラムにUNIXフィルターセマンティクスが魔法のように与えられる、気の利いたperl機能を使用したいのですが、この機能にアクセスできるようにしたいです実際のファイルハンドル(または IO :: Handle オブジェクトなど) 、それでサブルーチンなどに渡すようなことができます。これを行う方法はありますか?
"角度演算子"を検索するため、この質問はグーグルにとって特に困難です。および「ファイルハンドル」角度演算子を使用してファイルハンドルから読み取る方法を教えてください。
解決
perldoc perlvar
から:
ARGV
@ARGV
のコマンドラインファイル名を反復処理する特別なファイルハンドル。通常、角度演算子<>
でnullファイルハンドルとして書き込まれます。現在、ARGV
には<>
演算子内でのみ魔法の効果があることに注意してください。他の場所では、<>
によって最後に開かれたファイルに対応する単なるファイルハンドルです。特に、ファイルハンドルを想定している関数にパラメーターとして\ * ARGV
を渡すと、関数が@ARGV
内のすべてのファイルの内容を自動的に読み取らない場合があります。 / p>
これは、「それを言うのは嫌いですが、あなたが望むことをしない」という質問のあなたの質問のすべての側面に答えると信じています一種の方法。あなたができることは、開くファイル名のリストを取る関数を作成し、これを行うことです:
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, 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;
}
次のように使用できます:
[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]:
出力:
<*> while <$it>;
}
出力:
<*>これはすでに Iterator :: Diamond
。 Iterator :: Diamondは、perlが&lt; ARGV&gt;
を読み取るときに使用する2引数オープンマジックも無効にします。さらに良いことに、他のすべての魔法を有効にすることなく、 '-'
をSTDINとして読み取ることができます。実際、私はその目的のために単一のファイルでそれを使用するかもしれません。