Frage

Ich mag die nette Perl-Funktion verwenden, wo aus dem leeren Winkel Operator <> Lese gibt magisch Ihr Programm UNIX Filter Semantik, aber ich möchte in der Lage sein, auf diese Funktion zuzugreifen durch eine tatsächliche Dateihandle (oder IO :: Objekt Griff, oder ähnliches), so dass ich die Dinge tun kann, wie es passiert in Subroutinen und so. Gibt es eine Möglichkeit, dies zu tun?

Diese Frage ist besonders schwer zu Google, weil die Suche nach „Winkel Operator“ und „Dateihandle“ nur mir erzählt, wie aus Handles den Winkel Betreiber zu lesen.

War es hilfreich?

Lösung

perldoc perlvar :

  
      
  • ARGV
  •   
     

Die spezielle Dateihandle, das iteriert über Kommandozeilen-Dateinamen in @ARGV. Normalerweise geschrieben als null Dateihandle in dem Winkel Operator <>. Beachten Sie, dass derzeit ARGV nur hat seine magische Wirkung im <> Operator; an anderer Stelle ist es nur eine einfache Dateihandle auf die letzte Datei von <> geöffnet entspricht. Insbesondere vorbei \*ARGV als Parameter an eine Funktion, die ein Dateihandle automatisch kann nicht dazu führen, dass Funktion erwartet, um den Inhalt aller Dateien in @ARGV zu lesen.

Ich glaube, dass alle Aspekte Ihrer Frage beantwortet in diesem „Ich hasse es zu sagen, aber es wird nicht das tun, was Sie wollen“ Art und Weise. Was Sie tun können, ist Funktionen zu machen, die eine Liste von Dateinamen, um zu öffnen, und dies tun:

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

Aber das ist wahrscheinlich das Beste, was Sie werden in der Lage sein zu verwalten.

Andere Tipps

Der Ausbau auf Chris Lutz Idee, hier ist eine sehr rudimentäre Implementierung:

#!/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;
}

, die verwendet werden können, wie:

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>;
}

Ausgabe:

[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]:

Es sieht aus wie dies bereits als Iterator::Diamond . Iterator :: Diamant deaktiviert auch die 2-Argument offene Magie, das Perl verwendet, wenn <ARGV> lesen. Noch besser ist, unterstützt es das Lesen '-' als STDIN, ohne damit alle anderen Zauber. In der Tat könnte ich es zu diesem Zweck verwenden, nur auf einzelne Dateien.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top