Sto provando a determinare se un dato scalar contiene un filehandle. Potrebbe essermi passato da un filehandle bareword (ovvero \*FH
), un filehandle lessicale, un IO :: Handle, un IO :: File, ecc. Finora, l'unica cosa che sembra essere coerente tra i vari sapori è che hanno tutti un reftype
di "GLOB"
.Qual è il modo migliore per determinare se uno scalare contiene un filehandle?
risposta
Utilizzare la funzione openhandle da Scalar::Util:
openhandle FH
Restituisce FH se FH può essere usato come filehandle ed è aperto, oppure FH è un handle legato . Altrimenti, undef restituisce .
$fh = openhandle(*STDIN); # \*STDIN $fh = openhandle(\*STDIN); # \*STDIN $fh = openhandle(*NOTOPEN); # undef $fh = openhandle("scalar"); # undef
L'implementazione corrente è simile a Greg Bacon's answer, ma ha alcuni test aggiuntivi.
Ricordate che si può fare questo:
$ perl -le '$fh = "STDOUT"; print $fh "Hi there"' Hi there
Questa è una stringa normale, ma ancora utile come filehandle.
Guardando il source of IO::Handle
, la sua opened
è un sottile wrapper fileno
, che ha una proprietà a portata di mano:
Restituisce il descrittore di file per un filehandle, o non definito se il filehandle non è aperto.
Ma c'è un avvertimento:
Filehandle collegati ad oggetti di memoria con nuove caratteristiche di apertura può restituire indefinito anche se sono aperti.
Sembra quindi che un test lungo le linee di
[email protected] = "";
my $fd = eval { fileno $maybefh };
my $valid = [email protected] && defined $fd;
farà quello che vuoi.
Il codice sotto controlli i rappresentanti delle
- in memoria oggetti
- nome filehandles
- gocce
- riferimenti glob
- nomi glob
- standard input
FileHandle
istanzeIO::File
casi- tubi
- FIFO
- prese
gestire direttamente:
#! /usr/bin/perl
use warnings;
use strict;
use Fatal qw/ open /;
use FileHandle;
use IO::File;
use IO::Socket::INET;
my $SLEEP = 5;
my $FIFO = "/tmp/myfifo";
unlink $FIFO;
my $pid = fork;
die "$0: fork" unless defined $pid;
if ($pid == 0) {
system("mknod", $FIFO, "p") == 0 or die "$0: mknod failed";
open my $fh, ">", $FIFO;
sleep $SLEEP;
exit 0;
}
else {
sleep 1 while !-e $FIFO;
}
my @ignored = (\*FH1,\*FH2);
my @handles = (
[0, "1", 1],
[0, "hashref", {}],
[0, "arrayref", []],
[0, "globref", \*INC],
[1, "in-memory", do {{ my $buf; open my $fh, "<", \$buf; $fh }}],
[1, "FH1 glob", do {{ open FH1, "<", "/dev/null"; *FH1 }}],
[1, "FH2 globref", do {{ open FH2, "<", "/dev/null"; \*FH2 }}],
[1, "FH3 string", do {{ open FH3, "<", "/dev/null"; "FH3" }}],
[1, "STDIN glob", \*STDIN],
[1, "plain read", do {{ open my $fh, "<", "/dev/null"; $fh }}],
[1, "plain write", do {{ open my $fh, ">", "/dev/null"; $fh }}],
[1, "FH read", FileHandle->new("< /dev/null")],
[1, "FH write", FileHandle->new("> /dev/null")],
[1, "I::F read", IO::File->new("< /dev/null")],
[1, "I::F write", IO::File->new("> /dev/null")],
[1, "pipe read", do {{ open my $fh, "sleep $SLEEP |"; $fh }}],
[1, "pipe write", do {{ open my $fh, "| sleep $SLEEP"; $fh }}],
[1, "FIFO read", do {{ open my $fh, "<", $FIFO; $fh }}],
[1, "socket", IO::Socket::INET->new(PeerAddr => "localhost:80")],
);
sub valid {
local [email protected];
my $fd = eval { fileno $_[0] };
[email protected] && defined $fd;
}
for (@handles) {
my($expect,$desc,$fh) = @$_;
print "$desc: ";
my $valid = valid $fh;
if (!$expect) {
print $valid ? "FAIL\n" : "PASS\n";
next;
}
if ($valid) {
close $fh;
$valid = valid $fh;
print $valid ? "FAIL\n" : "PASS\n";
}
else {
print "FAIL\n";
}
}
print "Waiting for sleeps to finish...\n";
Tutto passa su un 9.10 casella di Ubuntu, quindi l'avvertenza in materia di oggetti in memoria non sembra essere una preoccupazione per quella piattaforma almeno.
1: PASS hashref: PASS arrayref: PASS globref: PASS in-memory: PASS FH1 glob: PASS FH2 globref: PASS FH3 string: PASS STDIN glob: PASS plain read: PASS plain write: PASS FH read: PASS FH write: PASS I::F read: PASS I::F write: PASS pipe read: PASS pipe write: PASS FIFO read: PASS socket: PASS
Sembra che 'tell' non sia portabile e non riesce a rilevare cose valide:" Il valore di ritorno di tell() per i flussi standard come lo STDIN dipende dal sistema operativo: può restituire -1 o qualcos'altro. su pipe, fifos e socket solitamente restituisce -1. " –
@Che bella cattura. Vedi risposta aggiornata. –
Davvero fantastico. Mi chiedo perché non ci sia già qualcosa di simile su CPAN. –
Ecco un estratto dal File::Copy determinare se una variabile è un handle di file:
my $from_a_handle = (ref($from)
? (ref($from) eq 'GLOB'
|| UNIVERSAL::isa($from, 'GLOB')
|| UNIVERSAL::isa($from, 'IO::Handle'))
: (ref(\$from) eq 'GLOB'));
Eww. 'UNIVERSAL :: isa' è un cattivo modo cattivo di fare isa. Preferirei 'eval {$ from-> isa ('GLOB')}' in modo che l'ereditarietà e l'override funzionino correttamente. Così dice [la documentazione di isa.] (Http://search.cpan.org/~jesse/perl-5.12.1/lib/UNIVERSAL.pm). Voglio dire, l'esempio che danno per cosa NON fare è '$ is_io = UNIVERSAL :: isa ($ fd," IO :: Handle "); # BAD! ' –
@Robert P: In realtà per GLOB (e altri tipi di riferimento di base) l'ultima raccomandazione è di usare Scalar :: Util :: reftype(). Mentre concordo un po 'con tutto questo, l'utilizzo del codice precedente ti darà gli stessi risultati di File :: Copy, un modulo principale, e dovresti fare qualche sforzo per far sì che non funzioni. – runrig
@Robert P: E ho avuto una discussione su questo argomento su PerlMonks (http://www.perlmonks.org/?node_id=615015) senza una vera risposta conclusiva per ciò che è la migliore pratica corrente. – runrig
io_from_any
from IO::Handle::Util
si occupa di aggiornare qualsiasi cosa a qualcosa di sano.
C'è anche ['wraphandle' da' IO :: Wrap'] (http://p3rl.org/IO::Wrap) ... –
Ma qualsiasi scalare contiene qualcosa che potrebbe essere utilizzato come un filehandle. Le stringhe possono essere filehandle: sono maniglie dei pacchetti, quindi.
Per questo motivo abbiamo sempre utilizzato Symbol::qualify()
. Non so se questo è ancora il "modo" che è comunemente sostenuto, ma funzionerà se si superano gli handle di bareword (che sono solo stringhe). Controlla il pacchetto caller
, qualificandolo in modo appropriato. anche qui Symbol::qualify_to_ref()
, che potrebbe essere più vicino a quello che stai cercando.
Ecco come funzionano entrambi. Nell'output seguito:
- Il primo elemento i => elenco è ciò che viene effettuato tramite
qualify
- Il secondo elemento nell'elenco => è ciò che viene rilasciato da
qualify_to_ref
- Il terzo elemento della => elenco è presentare
fileno
rendimenti sul secondo punto
lo script che produce questo è riportato qui di seguito:
off to NotMain
string "stderr" => main::stderr, GLOB(0x811720), fileno 2
string *stderr => *NotMain::stderr, GLOB(0x879ec0), fileno undef
string *sneeze => *NotMain::sneeze, GLOB(0x811e90), fileno undef
string *STDERR => *main::STDERR, GLOB(0x835260), fileno 2
back to main
string *stderr => *main::stderr, GLOB(0x879ec0), fileno 2
string "STDOUT" => main::STDOUT, GLOB(0x8116c0), fileno 1
string *STDOUT => *main::STDOUT, GLOB(0x811e90), fileno 1
string *STDOUT{IO} => IO::File=IO(0x8116d0), GLOB(0x811e90), fileno 1
string \*STDOUT => GLOB(0x8116c0), GLOB(0x8116c0), fileno 1
string "sneezy" => main::sneezy, GLOB(0x879ec0), fileno undef
string "hard to type" => main::hard to type, GLOB(0x8039e0), fileno 3
string $new_fh => IO::Handle=GLOB(0x8046c0), IO::Handle=GLOB(0x8046c0), fileno undef
string "GLOBAL" => main::GLOBAL, GLOB(0x891ff0), fileno 3
string *GLOBAL => *main::GLOBAL, GLOB(0x835260), fileno 3
string $GLOBAL => main::/dev/null, GLOB(0x817320), fileno 3
string $null => GLOB(0x8907d0), GLOB(0x8907d0), fileno 4
off to NotMain
glob "stderr" => main::stderr, GLOB(0x811720), fileno 2
glob stderr => main::stderr, GLOB(0x811720), fileno 2
glob sneeze => main::sneeze, GLOB(0x81e490), fileno undef
glob *sneeze => GLOB(0x892b90), GLOB(0x892b90), fileno undef
glob *stderr => GLOB(0x892710), GLOB(0x892710), fileno undef
glob *STDERR => GLOB(0x811700), GLOB(0x811700), fileno 2
back to main
glob *stderr => GLOB(0x811720), GLOB(0x811720), fileno 2
glob STDOUT => main::STDOUT, GLOB(0x8116c0), fileno 1
glob "STDOUT" => main::STDOUT, GLOB(0x8116c0), fileno 1
glob *STDOUT => GLOB(0x8116c0), GLOB(0x8116c0), fileno 1
glob *STDOUT{IO} => IO::File=IO(0x8116d0), GLOB(0x811d50), fileno 1
glob \*STDOUT => GLOB(0x8116c0), GLOB(0x8116c0), fileno 1
glob sneezy => main::sneezy, GLOB(0x879ec0), fileno undef
glob "sneezy" => main::sneezy, GLOB(0x879ec0), fileno undef
glob "hard to type" => main::hard to type, GLOB(0x8039e0), fileno 3
glob $new_fh => IO::Handle=GLOB(0x8046c0), IO::Handle=GLOB(0x8046c0), fileno undef
glob GLOBAL => main::GLOBAL, GLOB(0x891ff0), fileno 3
glob $GLOBAL => main::/dev/null, GLOB(0x817320), fileno 3
glob *GLOBAL => GLOB(0x891ff0), GLOB(0x891ff0), fileno 3
glob $null => GLOB(0x8907d0), GLOB(0x8907d0), fileno 4
Ed ecco lo script che generano quella uscita:
eval 'exec perl $0 ${1+"[email protected]"}'
if 0;
use 5.010_000;
use strict;
use autodie;
use warnings qw[ FATAL all ];
use Symbol;
use IO::Handle;
#define exec(arg)
BEGIN { exec("cpp $0 | $^X") } # nyah nyah nyah-NYAH nhah!!
#undef exec
#define CPP(FN, ARG) printf(" %6s %s => %s\n", main::short("FN"), q(ARG), FN(ARG))
#define QS(ARG) CPP(main::qual_string, ARG)
#define QG(ARG) CPP(main::qual_glob, ARG)
#define NL say ""
sub comma(@);
sub short($);
sub qual($);
sub qual_glob(*);
sub qual_string($);
$| = 1;
main();
exit();
sub main {
our $GLOBAL = "/dev/null";
open GLOBAL;
my $new_fh = new IO::Handle;
open(my $null, "/dev/null");
for my $str ($GLOBAL, "hard to type") {
no strict "refs";
*$str = *GLOBAL{IO};
}
fake_qs();
QS( *stderr );
QS( "STDOUT" );
QS( *STDOUT );
QS( *STDOUT{IO} );
QS(\*STDOUT );
QS("sneezy" );
QS("hard to type");
QS($new_fh );
QS("GLOBAL" );
QS(*GLOBAL );
QS($GLOBAL );
QS($null );
NL;
fake_qg();
QG( *stderr );
QG( STDOUT );
QG( "STDOUT" );
QG( *STDOUT );
QG( *STDOUT{IO} );
QG(\*STDOUT );
QG( sneezy );
QG("sneezy" );
QG("hard to type");
QG($new_fh );
QG( GLOBAL );
QG($GLOBAL );
QG(*GLOBAL );
QG($null );
NL;
}
package main;
sub comma(@) { join(", " => @_) }
sub qual_string($) {
my $string = shift();
return qual($string);
}
sub qual_glob(*) {
my $handle = shift();
return qual($handle);
}
sub qual($) {
my $thingie = shift();
my $qname = qualify($thingie);
my $qref = qualify_to_ref($thingie);
my $fnum = do { no autodie; fileno($qref) };
$fnum = "undef" unless defined $fnum;
return comma($qname, $qref, "fileno $fnum");
}
sub short($) {
my $name = shift();
$name =~ s/.*_//;
return $name;
}
sub fake_qg { &NotMain::fake_qg }
sub fake_qs { &NotMain::fake_qs }
package NotMain; # this is just wicked
sub fake_qg {
say "off to NotMain";
QG( "stderr" );
QG( stderr );
QG( sneeze );
QG( *sneeze );
QG( *stderr );
QG( *STDERR );
say "back to main";
}
sub fake_qs {
say "off to NotMain";
package NotMain;
QS( "stderr" );
QS( *stderr );
QS( *sneeze );
QS( *STDERR );
say "back to main";
}
Cosa posso dire? A volte mi manca davvero il preprocessore C.
I just so questo mi farò parlare di. ☺
Hey guarda, quello stupido windbag altrimenti noto come 'perlcritic' non è nemmeno kvetch su unario 'open'. Mostra cosa * loro * sanno! – tchrist
Io tendo ad usare:
eval { $fh->can('readline') }
O posso ('print') nel caso di maniglie ho intenzione di scrivere a. Questo è principalmente dovuto al fatto che in realtà voglio solo trattare i filehandle in modo OO, quindi questo risolve accuratamente se l'obiettivo può fare ciò che mi aspetto da esso.Se hai già controllato la definizione di $ fh, probabilmente puoi lasciare la valutazione.
- 1. qual è il modo migliore per determinare se un doppio non è zero
- 2. Qual è il modo migliore per determinare se una pagina Web è per dispositivi mobili?
- 3. Qual è il modo migliore per verificare se una stringa contiene un URL in Java/Android?
- 4. Qual è il modo migliore per determinare se System.DateTime è mezzanotte?
- 5. OpenCV: Qual è il modo più semplice per dividere un Mat con uno scalare
- 6. Qual è il modo più efficace per determinare se un grafico diretto è collegato singolarmente?
- 7. Il modo più efficace per determinare se una tabella Lua è vuota (non contiene voci)?
- 8. Qual è il modo più pitonico per determinare l'endianità?
- 9. Qual è il modo migliore per verificare se un attributo esiste ed è impostato?
- 10. Qual è il modo migliore per determinare che Tomcat è stato avviato con node.js
- 11. Qual è il modo migliore per rilevare se è disponibile un server proxy?
- 12. C'è un modo per testare se uno scalare è stato o meno univoco?
- 13. Qual è il modo migliore per tracciare l'esecuzione di JavaScript?
- 14. Qual è un modo migliore per verificare se una stringa è un numero intero su iPhone?
- 15. Qual è il modo migliore per costruire un NSCompoundPredicate complesso?
- 16. Qual è il modo migliore per scrivere se/else se/else se/else in HIVE?
- 17. Qual è il modo migliore per chiudere un ramo Mercurial?
- 18. Qual è il modo migliore per ridimensionare un oggetto BitmapData?
- 19. Qual è il modo migliore per verificare se un UIAlertController è già presente?
- 20. qual è il modo migliore per determinare l'altezza di un DIV prima che sia visibile sulla pagina web?
- 21. Qual è il modo migliore/più breve per convertire un Iterable in uno Stream, in Dart?
- 22. Qual è il modo migliore per vedere se un RadioButtonList ha un valore selezionato?
- 23. Qual è il modo più semplice per verificare se la stringa contiene un tag immagine?
- 24. Qual è il modo migliore per generare una sitemap?
- 25. Un modo per determinare se un elemento è stato imballato?
- 26. Il modo migliore per verificare se un elenco a discesa contiene un valore?
- 27. Il modo migliore per sapere se JQuery è disponibile?
- 28. In Rails, qual è il modo migliore per aggiornare un record o crearne uno nuovo se non esiste?
- 29. Qual è il modo migliore per analizzare questo in C++?
- 30. Qual è il modo migliore per documentare il codice f #?
possibile duplicato di [Come faccio a sapere quale tipo di valore si trova in una variabile Perl?] (Http://stackoverflow.com/questions/1731333/how-do-i-tell-what-type-of-value -is-in-a-perl-variabile) – Ether
Oops spiacente, quello non è un duplicato esatto. Vorrei poter ritrattare quel voto ravvicinato! (Ma il collegamento è ancora piuttosto rilevante.) – Ether
Vedi [Quando fa 'ref ($ variabile)' restituisce 'IO'?] (Http://stackoverflow.com/questions/2955428/when-does-refvariable-return-io) per una domanda simile. – Zaid