📄 perlfaq5.1
字号:
.PP.Vb 2\& open my $in, \*(Aq<\*(Aq, $file or die "Can\*(Aqt read old file: $!"\& open my $out, \*(Aq>\*(Aq, "$file.new" or die "Can\*(Aqt write new file: $!";\&\& my @lines = do { local $/; <$in> }; # slurp!\&\& # do your magic here\&\& print $out @lines;.Ve.PPModules such as \f(CW\*(C`File::Slurp\*(C'\fR and \f(CW\*(C`Tie::File\*(C'\fR can help with thattoo. If you can, however, avoid reading the entire file at once. Perlwon't give that memory back to the operating system until the processfinishes..PPYou can also use Perl one-liners to modify a file in-place. Thefollowing changes all 'Fred' to 'Barney' in \fIinFile.txt\fR, overwritingthe file with the new contents. With the \f(CW\*(C`\-p\*(C'\fR switch, Perl wraps a\&\f(CW\*(C`while\*(C'\fR loop around the code you specify with \f(CW\*(C`\-e\*(C'\fR, and \f(CW\*(C`\-i\*(C'\fR turnson in-place editing. The current line is in \f(CW$_\fR. With \f(CW\*(C`\-p\*(C'\fR, Perlautomatically prints the value of \f(CW$_\fR at the end of the loop. Seeperlrun for more details..PP.Vb 1\& perl \-pi \-e \*(Aqs/Fred/Barney/\*(Aq inFile.txt.Ve.PPTo make a backup of \f(CW\*(C`inFile.txt\*(C'\fR, give \f(CW\*(C`\-i\*(C'\fR a file extension to add:.PP.Vb 1\& perl \-pi.bak \-e \*(Aqs/Fred/Barney/\*(Aq inFile.txt.Ve.PPTo change only the fifth line, you can add a test checking \f(CW$.\fR, theinput line number, then only perform the operation when the testpasses:.PP.Vb 1\& perl \-pi \-e \*(Aqs/Fred/Barney/ if $. == 5\*(Aq inFile.txt.Ve.PPTo add lines before a certain line, you can add a line (or lines!)before Perl prints \f(CW$_\fR:.PP.Vb 1\& perl \-pi \-e \*(Aqprint "Put before third line\en" if $. == 3\*(Aq inFile.txt.Ve.PPYou can even add a line to the beginning of a file, since the currentline prints at the end of the loop:.PP.Vb 1\& perl \-pi \-e \*(Aqprint "Put before first line\en" if $. == 1\*(Aq inFile.txt.Ve.PPTo insert a line after one already in the file, use the \f(CW\*(C`\-n\*(C'\fR switch.It's just like \f(CW\*(C`\-p\*(C'\fR except that it doesn't print \f(CW$_\fR at the end ofthe loop, so you have to do that yourself. In this case, print \f(CW$_\fRfirst, then print the line that you want to add..PP.Vb 1\& perl \-ni \-e \*(Aqprint; print "Put after fifth line\en" if $. == 5\*(Aq inFile.txt.Ve.PPTo delete lines, only print the ones that you want..PP.Vb 1\& perl \-ni \-e \*(Aqprint unless /d/\*(Aq inFile.txt\&\& ... or ...\&\& perl \-pi \-e \*(Aqnext unless /d/\*(Aq inFile.txt.Ve.Sh "How do I count the number of lines in a file?".IX Xref "file, counting lines lines line".IX Subsection "How do I count the number of lines in a file?"One fairly efficient way is to count newlines in the file. Thefollowing program uses a feature of tr///, as documented in perlop.If your text file doesn't end with a newline, then it's not really aproper text file, so this may report one fewer line than you expect..PP.Vb 6\& $lines = 0;\& open(FILE, $filename) or die "Can\*(Aqt open \`$filename\*(Aq: $!";\& while (sysread FILE, $buffer, 4096) {\& $lines += ($buffer =~ tr/\en//);\& }\& close FILE;.Ve.PPThis assumes no funny games with newline translations..ie n .Sh "How can I use Perl's ""\-i"" option from within a program?".el .Sh "How can I use Perl's \f(CW\-i\fP option from within a program?".IX Xref "-i in-place".IX Subsection "How can I use Perl's -i option from within a program?"\&\f(CW\*(C`\-i\*(C'\fR sets the value of Perl's \f(CW$^I\fR variable, which in turn affectsthe behavior of \f(CW\*(C`<>\*(C'\fR; see perlrun for more details. Bymodifying the appropriate variables directly, you can get the samebehavior within a larger program. For example:.PP.Vb 10\& # ...\& {\& local($^I, @ARGV) = (\*(Aq.orig\*(Aq, glob("*.c"));\& while (<>) {\& if ($. == 1) {\& print "This line should appear at the top of each file\en";\& }\& s/\eb(p)earl\eb/${1}erl/i; # Correct typos, preserving case\& print;\& close ARGV if eof; # Reset $.\& }\& }\& # $^I and @ARGV return to their old values here.Ve.PPThis block modifies all the \f(CW\*(C`.c\*(C'\fR files in the current directory,leaving a backup of the original data from each file in a new\&\f(CW\*(C`.c.orig\*(C'\fR file..Sh "How can I copy a file?".IX Xref "copy file, copy".IX Subsection "How can I copy a file?"(contributed by brian d foy).PPUse the File::Copy module. It comes with Perl and can do atrue copy across file systems, and it does its magic ina portable fashion..PP.Vb 1\& use File::Copy;\&\& copy( $original, $new_copy ) or die "Copy failed: $!";.Ve.PPIf you can't use File::Copy, you'll have to do the work yourself:open the original file, open the destination file, then printto the destination file as you read the original..Sh "How do I make a temporary file name?".IX Xref "file, temporary".IX Subsection "How do I make a temporary file name?"If you don't need to know the name of the file, you can use \f(CW\*(C`open()\*(C'\fRwith \f(CW\*(C`undef\*(C'\fR in place of the file name. The \f(CW\*(C`open()\*(C'\fR functioncreates an anonymous temporary file..PP.Vb 1\& open my $tmp, \*(Aq+>\*(Aq, undef or die $!;.Ve.PPOtherwise, you can use the File::Temp module..PP.Vb 1\& use File::Temp qw/ tempfile tempdir /;\&\& $dir = tempdir( CLEANUP => 1 );\& ($fh, $filename) = tempfile( DIR => $dir );\&\& # or if you don\*(Aqt need to know the filename\&\& $fh = tempfile( DIR => $dir );.Ve.PPThe File::Temp has been a standard module since Perl 5.6.1. If youdon't have a modern enough Perl installed, use the \f(CW\*(C`new_tmpfile\*(C'\fRclass method from the IO::File module to get a filehandle opened forreading and writing. Use it if you don't need to know the file's name:.PP.Vb 3\& use IO::File;\& $fh = IO::File\->new_tmpfile()\& or die "Unable to make new temporary file: $!";.Ve.PPIf you're committed to creating a temporary file by hand, use theprocess \s-1ID\s0 and/or the current time-value. If you need to have manytemporary files in one process, use a counter:.PP.Vb 4\& BEGIN {\& use Fcntl;\& my $temp_dir = \-d \*(Aq/tmp\*(Aq ? \*(Aq/tmp\*(Aq : $ENV{TMPDIR} || $ENV{TEMP};\& my $base_name = sprintf "%s/%d\-%d\-0000", $temp_dir, $$, time;\&\& sub temp_file {\& local *FH;\& my $count = 0;\& until( defined(fileno(FH)) || $count++ > 100 ) {\& $base_name =~ s/\-(\ed+)$/"\-" . (1 + $1)/e;\& # O_EXCL is required for security reasons.\& sysopen FH, $base_name, O_WRONLY|O_EXCL|O_CREAT;\& }\&\& if( defined fileno(FH) ) {\& return (*FH, $base_name);\& }\& else {\& return ();\& }\& }\& \& }.Ve.Sh "How can I manipulate fixed-record-length files?".IX Xref "fixed-length file, fixed-length records".IX Subsection "How can I manipulate fixed-record-length files?"The most efficient way is using \fIpack()\fR and\&\fIunpack()\fR. This is faster than using\&\fIsubstr()\fR when taking many, many strings. It isslower for just a few..PPHere is a sample chunk of code to break up and put back together againsome fixed-format input lines, in this case from the output of a normal,Berkeley-style ps:.PP.Vb 10\& # sample input line:\& # 15158 p5 T 0:00 perl /home/tchrist/scripts/now\-what\& my $PS_T = \*(AqA6 A4 A7 A5 A*\*(Aq;\& open my $ps, \*(Aq\-|\*(Aq, \*(Aqps\*(Aq;\& print scalar <$ps>;\& my @fields = qw( pid tt stat time command );\& while (<$ps>) {\& my %process;\& @process{@fields} = unpack($PS_T, $_);\& for my $field ( @fields ) {\& print "$field: <$process{$field}>\en";\& }\& print \*(Aqline=\*(Aq, pack($PS_T, @process{@fields} ), "\en";\& }.Ve.PPWe've used a hash slice in order to easily handle the fields of each row.Storing the keys in an array means it's easy to operate on them as agroup or loop over them with for. It also avoids polluting the programwith global variables and using symbolic references..Sh "How can I make a filehandle local to a subroutine? How do I pass filehandles between subroutines? How do I make an array of filehandles?".IX Xref "filehandle, local filehandle, passing filehandle, reference".IX Subsection "How can I make a filehandle local to a subroutine? How do I pass filehandles between subroutines? How do I make an array of filehandles?"As of perl5.6, \fIopen()\fR autovivifies file and directory handlesas references if you pass it an uninitialized scalar variable.You can then pass these references just like any other scalar,and use them in the place of named handles..PP.Vb 1\& open my $fh, $file_name;\&\& open local $fh, $file_name;\&\& print $fh "Hello World!\en";\&\& process_file( $fh );.Ve.PPIf you like, you can store these filehandles in an array or a hash.If you access them directly, they aren't simple scalars and youneed to give \f(CW\*(C`print\*(C'\fR a little help by placing the filehandlereference in braces. Perl can only figure it out on its own whenthe filehandle reference is a simple scalar..PP.Vb 1\& my @fhs = ( $fh1, $fh2, $fh3 );\&\& for( $i = 0; $i <= $#fhs; $i++ ) {\& print {$fhs[$i]} "just another Perl answer, \en";\& }.Ve.PPBefore perl5.6, you had to deal with various typeglob idiomswhich you may see in older code..PP.Vb 3\& open FILE, "> $filename";\& process_typeglob( *FILE );\& process_reference( \e*FILE );\&\& sub process_typeglob { local *FH = shift; print FH "Typeglob!" }\& sub process_reference { local $fh = shift; print $fh "Reference!" }.Ve.PPIf you want to create many anonymous handles, you shouldcheck out the Symbol or IO::Handle modules..Sh "How can I use a filehandle indirectly?".IX Xref "filehandle, indirect".IX Subsection "How can I use a filehandle indirectly?"An indirect filehandle is using something other than a symbolin a place that a filehandle is expected. Here are waysto get indirect filehandles:.PP.Vb 5\& $fh = SOME_FH; # bareword is strict\-subs hostile\& $fh = "SOME_FH"; # strict\-refs hostile; same package only\& $fh = *SOME_FH; # typeglob\& $fh = \e*SOME_FH; # ref to typeglob (bless\-able)\& $fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob.Ve.PPOr, you can use the \f(CW\*(C`new\*(C'\fR method from one of the IO::* modules tocreate an anonymous filehandle, store that in a scalar variable,and use it as though it were a normal filehandle..PP.Vb 2\& use IO::Handle; # 5.004 or higher\& $fh = IO::Handle\->new();.Ve.PPThen use any of those as you would a normal filehandle. Anywhere thatPerl is expecting a filehandle, an indirect filehandle may be usedinstead. An indirect filehandle is just a scalar variable that containsa filehandle. Functions like \f(CW\*(C`print\*(C'\fR, \f(CW\*(C`open\*(C'\fR, \f(CW\*(C`seek\*(C'\fR, orthe \f(CW\*(C`<FH>\*(C'\fR diamond operator will accept either a named filehandleor a scalar variable containing one:.PP.Vb 4\& ($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);\& print $ofh "Type it: ";\& $got = <$ifh>\& print $efh "What was that: $got";.Ve.PPIf you're passing a filehandle to a function, you can writethe function in two ways:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -