📄 perlfaq5.pod
字号:
or a scalar variable containing one: ($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR); print $ofh "Type it: "; $got = <$ifh> print $efh "What was that: $got";If you're passing a filehandle to a function, you can writethe function in two ways: sub accept_fh { my $fh = shift; print $fh "Sending to indirect filehandle\n"; }Or it can localize a typeglob and use the filehandle directly: sub accept_fh { local *FH = shift; print FH "Sending to localized filehandle\n"; }Both styles work with either objects or typeglobs of real filehandles.(They might also work with strings under some circumstances, but thisis risky.) accept_fh(*STDOUT); accept_fh($handle);In the examples above, we assigned the filehandle to a scalar variablebefore using it. That is because only simple scalar variables, notexpressions or subscripts of hashes or arrays, can be used withbuilt-ins like C<print>, C<printf>, or the diamond operator. Usingsomething other than a simple scalar variable as a filehandle isillegal and won't even compile: @fd = (*STDIN, *STDOUT, *STDERR); print $fd[1] "Type it: "; # WRONG $got = <$fd[0]> # WRONG print $fd[2] "What was that: $got"; # WRONGWith C<print> and C<printf>, you get around this by using a block andan expression where you would place the filehandle: print { $fd[1] } "funny stuff\n"; printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559; # Pity the poor deadbeef.That block is a proper block like any other, so you can put morecomplicated code there. This sends the message out to one of two places: $ok = -x "/bin/cat"; print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n"; print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";This approach of treating C<print> and C<printf> like object methodscalls doesn't work for the diamond operator. That's because it's areal operator, not just a function with a comma-less argument. Assumingyou've been storing typeglobs in your structure as we did above, youcan use the built-in function named C<readline> to read a record justas C<< <> >> does. Given the initialization shown above for @fd, thiswould work, but only because readline() requires a typeglob. It doesn'twork with objects or strings, which might be a bug we haven't fixed yet. $got = readline($fd[0]);Let it be noted that the flakiness of indirect filehandles is notrelated to whether they're strings, typeglobs, objects, or anything else.It's the syntax of the fundamental operators. Playing the objectgame doesn't help you at all here.=head2 How can I set up a footer format to be used with write()?X<footer>There's no builtin way to do this, but L<perlform> has a couple oftechniques to make it possible for the intrepid hacker.=head2 How can I write() into a string?X<write, into a string>See L<perlform/"Accessing Formatting Internals"> for an C<swrite()> function.=head2 How can I open a filehandle to a string?X<string>, X<open>, X<IO::Scalar>, X<filehandle>(contributed by Peter J. Holzer, hjp-usenet2@hjp.at)Since Perl 5.8.0, you can pass a reference to a scalar instead of thefilename to create a file handle which you can used to read from or write toa string: open(my $fh, '>', \$string) or die "Could not open string for writing"; print $fh "foo\n"; print $fh "bar\n"; # $string now contains "foo\nbar\n" open(my $fh, '<', \$string) or die "Could not open string for reading"; my $x = <$fh>; # $x now contains "foo\n"With older versions of Perl, the C<IO::String> module provides similarfunctionality. =head2 How can I output my numbers with commas added?X<number, commify>(contributed by brian d foy and Benjamin Goldberg)You can use L<Number::Format> to separate places in a number.It handles locale information for those of you who want to insertfull stops instead (or anything else that they want to use,really).This subroutine will add commas to your number: sub commify { local $_ = shift; 1 while s/^([-+]?\d+)(\d{3})/$1,$2/; return $_; }This regex from Benjamin Goldberg will add commas to numbers: s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;It is easier to see with comments: s/( ^[-+]? # beginning of number. \d+? # first digits before first comma (?= # followed by, (but not included in the match) : (?>(?:\d{3})+) # some positive multiple of three digits. (?!\d) # an *exact* multiple, not x * 3 + 1 or whatever. ) | # or: \G\d{3} # after the last group, get three digits (?=\d) # but they have to have more digits after them. )/$1,/xg;=head2 How can I translate tildes (~) in a filename?X<tilde> X<tilde expansion>Use the <> (glob()) operator, documented in L<perlfunc>. Olderversions of Perl require that you have a shell installed that grokstildes. Recent perl versions have this feature built in. TheFile::KGlob module (available from CPAN) gives more portable globfunctionality.Within Perl, you may use this directly: $filename =~ s{ ^ ~ # find a leading tilde ( # save this in $1 [^/] # a non-slash character * # repeated 0 or more times (0 means me) ) }{ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} ) }ex;=head2 How come when I open a file read-write it wipes it out?X<clobber> X<read-write> X<clobbering> X<truncate> X<truncating>Because you're using something like this, which truncates the file andI<then> gives you read-write access: open(FH, "+> /path/name"); # WRONG (almost always)Whoops. You should instead use this, which will fail if the filedoesn't exist. open(FH, "+< /path/name"); # open for updateUsing ">" always clobbers or creates. Using "<" never doeseither. The "+" doesn't change this.Here are examples of many kinds of file opens. Those using sysopen()all assume use Fcntl;To open file for reading: open(FH, "< $path") || die $!; sysopen(FH, $path, O_RDONLY) || die $!;To open file for writing, create new file if needed or else truncate old file: open(FH, "> $path") || die $!; sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT) || die $!; sysopen(FH, $path, O_WRONLY|O_TRUNC|O_CREAT, 0666) || die $!;To open file for writing, create new file, file must not exist: sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT) || die $!; sysopen(FH, $path, O_WRONLY|O_EXCL|O_CREAT, 0666) || die $!;To open file for appending, create if necessary: open(FH, ">> $path") || die $!; sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT) || die $!; sysopen(FH, $path, O_WRONLY|O_APPEND|O_CREAT, 0666) || die $!;To open file for appending, file must exist: sysopen(FH, $path, O_WRONLY|O_APPEND) || die $!;To open file for update, file must exist: open(FH, "+< $path") || die $!; sysopen(FH, $path, O_RDWR) || die $!;To open file for update, create file if necessary: sysopen(FH, $path, O_RDWR|O_CREAT) || die $!; sysopen(FH, $path, O_RDWR|O_CREAT, 0666) || die $!;To open file for update, file must not exist: sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT) || die $!; sysopen(FH, $path, O_RDWR|O_EXCL|O_CREAT, 0666) || die $!;To open a file without blocking, creating if necessary: sysopen(FH, "/foo/somefile", O_WRONLY|O_NDELAY|O_CREAT) or die "can't open /foo/somefile: $!":Be warned that neither creation nor deletion of files is guaranteed tobe an atomic operation over NFS. That is, two processes might bothsuccessfully create or unlink the same file! Therefore O_EXCLisn't as exclusive as you might wish.See also the new L<perlopentut> if you have it (new for 5.6).=head2 Why do I sometimes get an "Argument list too long" when I use E<lt>*E<gt>?X<argument list too long>The C<< <> >> operator performs a globbing operation (see above).In Perl versions earlier than v5.6.0, the internal glob() operator forkscsh(1) to do the actual glob expansion, butcsh can't handle more than 127 items and so gives the error messageC<Argument list too long>. People who installed tcsh as csh won'thave this problem, but their users may be surprised by it.To get around this, either upgrade to Perl v5.6.0 or later, do the globyourself with readdir() and patterns, or use a module like File::KGlob,one that doesn't use the shell to do globbing.=head2 Is there a leak/bug in glob()?X<glob>Due to the current implementation on some operating systems, when youuse the glob() function or its angle-bracket alias in a scalarcontext, you may cause a memory leak and/or unpredictable behavior. It'sbest therefore to use glob() only in list context.=head2 How can I open a file with a leading ">" or trailing blanks?X<filename, special characters>(contributed by Brian McCauley)The special two argument form of Perl's open() function ignorestrailing blanks in filenames and infers the mode from certain leadingcharacters (or a trailing "|"). In older versions of Perl this was theonly version of open() and so it is prevalent in old code and books.Unless you have a particular reason to use the two argument form youshould use the three argument form of open() which does not treat anycharacters in the filename as special. open FILE, "<", " file "; # filename is " file " open FILE, ">", ">file"; # filename is ">file"=head2 How can I reliably rename a file?X<rename> X<mv> X<move> X<file, rename> X<ren>If your operating system supports a proper mv(1) utility or itsfunctional equivalent, this works: rename($old, $new) or system("mv", $old, $new);It may be more portable to use the File::Copy module instead.You just copy to the new file to the new name (checking returnvalues), then delete the old one. This isn't really the samesemantically as a rename(), which preserves meta-information likepermissions, timestamps, inode info, etc.Newer versions of File::Copy export a move() function.=head2 How can I lock a file?X<lock> X<file, lock> X<flock>Perl's builtin flock() function (see L<perlfunc> for details) will callflock(2) if that exists, fcntl(2) if it doesn't (on perl version 5.004 andlater), and lockf(3) if neither of the two previous system calls exists.On some systems, it may even use a different form of native locking.Here are some gotchas with Perl's flock():=over 4=item 1Produces a fatal error if none of the three system calls (or theirclose equivalent) exists.=item 2lockf(3) does not provide shared locking, and requires that thefilehandle be open for writing (or appending, or read/writing).=item 3Some versions of flock() can't lock files over a network (e.g. on NFS filesystems), so you'd need to force the use of fcntl(2) when you build Perl.But even this is dubious at best. See the flock entry of L<perlfunc>and the F<INSTALL> file in the source distribution for information onbuilding Perl to do this.Two potentially non-obvious but traditional flock semantics are thatit waits indefinitely until the lock is granted, and that its locks areI<merely advisory>. Such discretionary locks are more flexible, butoffer fewer guarantees. This means that files locked with flock() maybe modified by programs that do not also use flock(). Cars that stopfor red lights get on well with each other, but not with cars that don'tstop for red lights. See the perlport manpage, your port's specificdocumentation, or your system-specific local manpages for details. It'sbest to assume traditional behavior if you're writing portable programs.(If you're not, you should as always feel perfectly free to writefor your own system's idiosyncrasies (sometimes called "features").Slavish adherence to portability concerns shouldn't get in the way ofyour getting your job done.)For more information on file locking, see alsoL<perlopentut/"File Locking"> if you have it (new for 5.6).=back=head2 Why can't I just open(FH, "E<gt>file.lock")?X<lock, lockfile race condition>A common bit of code B<NOT TO USE> is this: sleep(3) while -e "file.lock"; # PLEASE DO NOT USE open(LCK, "> file.lock"); # THIS BROKEN CODEThis is a classic race condition: you take two steps to do somethingwhich must be done in one. That's why computer hardware provides anatomic test-and-set instruction. In theory, this "ought" to work: sysopen(FH, "file.lock", O_WRONLY|O_EXCL|O_CREAT) or die "can't open file.lock: $!";except that lamentably, file creation (and deletion) is not atomicover NFS, so this won't work (at least, not every time) over the net.Various schemes involving link() have been suggested, butthese tend to involve busy-wait, which is also less than desirable.=head2 I still don't get locking. I just want to increment the number in the file. How can I do this?X<counter> X<file, counter>Didn't anyone ever tell you web-page hit counters were useless?They don't count number of hits, they're a waste of time, and they serveonly to stroke the writer's vanity. It's better to pick a random number;they're more realistic.Anyway, this is what you can do if you can't help yourself. use Fcntl qw(:DEFAULT :flock); sysopen(FH, "numfile", O_RDWR|O_CREAT) or die "can't open numfile: $!"; flock(FH, LOCK_EX) or die "can't flock numfile: $!"; $num = <FH> || 0; seek(FH, 0, 0) or die "can't rewind numfile: $!"; truncate(FH, 0) or die "can't truncate numfile: $!"; (print FH $num+1, "\n") or die "can't write numfile: $!"; close FH or die "can't close numfile: $!";Here's a much better web-page hit counter: $hits = int( (time() - 850_000_000) / rand(1_000) );If the count doesn't impress your friends, then the code might. :-)=head2 All I want to do is append a small amount of text to the end of a file. Do I still have to use locking?X<append> X<file, append>If you are on a system that correctly implements flock() and you use theexample appending code from "perldoc -f flock" everything will be OKeven if the OS you are on doesn't implement append mode correctly (ifsuch a system exists.) So if you are happy to restrict yourself to OSsthat implement flock() (and that's not really much of a restriction)then that is what you should do.If you know you are only going to use a system that does correctlyimplement appending (i.e. not Win32) then you can omit the seek() fromthe code in the previous answer.If you know you are only writing code to run on an OS and filesystem thatdoes implement append mode correctly (a local filesystem on a modernUnix for example), and you keep the file in block-buffered mode and youwrite less than one buffer-full of output between each manual flushingof the buffer then each bufferload is almost guaranteed to be written tothe end of the file in one chunk without getting intermingled withanyone else's output. You can also use the syswrite() function which issimply a wrapper around your systems write(2) system call.There is still a small theoretical chance that a signal will interruptthe system level write() operation before completion. There is also apossibility that some STDIO implementations may call multiple systemlevel write()s even if the buffer was empty to start. There may be somesystems where this probability is reduced to zero.=head2 How do I randomly update a binary file?X<file, binary patch>If you're just trying to patch a binary, in many cases something assimple as this works: perl -i -pe 's{window manager}{window mangler}g' /usr/bin/emacsHowever, if you have fixed sized records, then you might do something morelike this: $RECSIZE = 220; # size of record, in bytes $recno = 37; # which record to update open(FH, "+<somewhere") || die "can't update somewhere: $!"; seek(FH, $recno * $RECSIZE, 0); read(FH, $record, $RECSIZE) == $RECSIZE || die "can't read record $recno: $!"; # munge the record seek(FH, -$RECSIZE, 1); print FH $record; close FH;Locking and error checking are left as an exercise for the reader.Don't forget them or you'll be quite sorry.=head2 How do I get a file's timestamp in perl?X<timestamp> X<file, timestamp>If you want to retrieve the time at which the file was lastread, written, or had its meta-data (owner, etc) changed,you use the B<-A>, B<-M>, or B<-C> file test operations asdocumented in L<perlfunc>. These retrieve the age of thefile (measured against the start-time of your program) in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -