.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "File::Util::Manual::Examples 3pm" .TH File::Util::Manual::Examples 3pm "2022-11-29" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" File::Util::Manual::Examples \- File::Util Examples .SH "VERSION" .IX Header "VERSION" version 4.201720 .SH "INTRODUCTION" .IX Header "INTRODUCTION" This manual subsection is fully comprised of simple examples of File::Util in greater depth than what you see in the main documentation, however to keep things simple, these examples are short, quick, and to the point. .PP For examples of full Programs using File::Util, take a look at the Cookbook at the File::Util::Cookbook. .SH "EXAMPLES" .IX Header "EXAMPLES" Many of these are demonstrated in the standalone scripts that come in the \&\*(L"examples\*(R" directory as part of this distribution. .PP Unless indicated otherwise, all of these short examples assume that you have started out with: .PP .Vb 2 \& use File::Util; \& my $f = File::Util\->new(); .Ve .PP The variable \f(CW$f\fR is used for simplicity here in the examples. In your actual programming you should refrain from using single-letter variables and use something more obvious instead, such as \f(CW$ftl\fR or \f(CW$futil\fR .SS "Get the contents of a file in a string" .IX Subsection "Get the contents of a file in a string" .Vb 1 \& my $contents = $f\->load_file( \*(Aqfilename\*(Aq ); \& \& \-OR\- \& \& my $contents = $f\->load_file( \*(Aq/path/to/filename\*(Aq ); \& \& \-OR\- \& \& my $contents = $f\->load_file( \*(AqC:\epath\eto\efilename\*(Aq ); .Ve .SS "Get the contents of a \s-1UTF\-8\s0 encoded file in a \s-1UTF\-8\s0 encoded string" .IX Subsection "Get the contents of a UTF-8 encoded file in a UTF-8 encoded string" .Vb 1 \& my $encoded_data = $f\->load_file( \*(Aqencoded.txt\*(Aq => { binmode => \*(Aqutf8\*(Aq } ); .Ve .SS "Get the contents of a file in an array of lines in the file" .IX Subsection "Get the contents of a file in an array of lines in the file" .Vb 1 \& my @contents = $f\->load_file( \*(Aqfilename\*(Aq => { as_lines => 1 } ); .Ve .SS "Get an open file handle for reading" .IX Subsection "Get an open file handle for reading" .Vb 4 \& my $fh = $f\->open_handle( \& file => \*(Aq/some/existing/file\*(Aq, \& mode => \*(Aqread\*(Aq \& ); \& \& \-OR\- \& \& # ... you can also use the shorter syntax: \& my $fh = $f\->open_handle( \*(Aq/some/existing/file\*(Aq => \*(Aqread\*(Aq ); \& \& # ... you can open a file handle to a UTF\-8 encoded file too \& my $fh = $f\->open_handle( \*(Aqencoded.txt\*(Aq => \*(Aqread\*(Aq => { binmode => \*(Aqutf8\*(Aq } ); \& \& # then use the filehandle like you would use any other file handle: \& while ( my $line = <$fh> ) { \& \& # ... do stuff with $line \& } \& \& close $fh or die $!; .Ve .SS "Get an open file handle for writing" .IX Subsection "Get an open file handle for writing" Opening a file for writing (write mode) will create the file if it doesn't already exist. The file handle is automatically locked for you with \fBflock()\fR if your system supports it. .PP .Vb 4 \& my $fh = $f\->open_handle( \& file => \*(Aq/some/file\*(Aq, \& mode => \*(Aqwrite\*(Aq \& ); \& \& \-OR\- \& \& # ... you can also use the shorter syntax: \& my $fh = $f\->open_handle( \*(Aq/some/file\*(Aq => \*(Aqwrite\*(Aq ); \& \& # ... you can open a file handle with UTF\-8 encoding support \& my $fh = $f\->open_handle( \*(Aq/some/file\*(Aq => \*(Aqwrite\*(Aq => { binmode => \*(Aqutf8\*(Aq } ); \& \& print $fh \*(AqHello world!\*(Aq; \& \& close $fh or die $!; .Ve .SS "Write to a new or existing file" .IX Subsection "Write to a new or existing file" .Vb 1 \& my $content = \*(AqPathelogically Eclectic Rubbish Lister\*(Aq; \& \& $f\->write_file( file => \*(Aqa new file.txt\*(Aq, content => $content ); \& \& \-OR\- \& \& # you can use the shorter syntax: \& $f\->write_file( \*(Aqa new file.txt\*(Aq => $content ); \& \& \-OR\- \& \& # write UTF\-8 encoded data also. the file will have UTF\-8 encoding: \& $f\->write_file( \*(Aqencoded.txt\*(Aq => $encoded_data => { binmode => \*(Aqutf8\*(Aq } ); .Ve .PP You can optionally specify a bitmask for a file if it doesn't exist yet. The bitmask is combined with the user's current umask for the creation mode of the file. (You should usually omit this.) .PP .Vb 5 \& $f\->write_file( \& file => \*(AqC:\esome\enew\efile.txt\*(Aq, \& content => $content \& bitmask => oct 777, \& ); \& \& \-OR\- \& \& $f\->write_file( \*(Aqfile.txt\*(Aq => $content => { bitmask => oct 777 } ); .Ve .SS "Warn if the file couldn't be written, instead of dying by default" .IX Subsection "Warn if the file couldn't be written, instead of dying by default" .Vb 7 \& $f\->write_file( \& \*(Aqfile.txt\*(Aq => $content, \& { \& onfail => \*(Aqwarn\*(Aq, \& bitmask => oct 777 \& } \& ); .Ve .SS "Conceal the error if the file couldn't be written (secure), but log it too" .IX Subsection "Conceal the error if the file couldn't be written (secure), but log it too" .Vb 1 \& # define a custom (secure) error handler \& \& $f\->write_file( \& \*(Aqfile.txt\*(Aq => $content => \& { \& bitmask => oct 777 \& onfail => sub { \& my ( $err, $stack ) = @_; \& \& # send the error message and stack trace to a logger of some kind... \& $logger\->log( $err . $stack ); \& \& # or send an email alert? \& send_email_alert_to_admin( $err ); #<< you\*(Aqll have to write that sub \& \& # return undef to indicate a problem (or you could die/exit too) \& return; \& } \& } \& ); .Ve .SS "Why not first check if the file is writeable/can be created" .IX Subsection "Why not first check if the file is writeable/can be created" .Vb 1 \& if ( $f\->is_writable( \*(Aq/root/some/file.txt\*(Aq ) ) { \& \& # ... now create/write to the file \& } .Ve .SS "Append to a new or existing file" .IX Subsection "Append to a new or existing file" .Vb 1 \& my $content = \*(AqThe fastest hunk of junk in the galaxy\*(Aq; \& \& $f\->write_file( \& file => \*(Aqmfalcon.spec\*(Aq, \& mode => \*(Aqappend\*(Aq, \& content => $content \& ); \& \& \-OR\- \& \& $f\->write_file( \*(Aqmfalcon.spec\*(Aq => $content => { mode => \*(Aqappend\*(Aq } ); .Ve .SS "Get the names of all files and subdirectories in a directory" .IX Subsection "Get the names of all files and subdirectories in a directory" .Vb 2 \& # option no_fsdots excludes "." and ".." from the list \& my @dirs_and_files = $f\->list_dir( \*(Aq/foo\*(Aq => { no_fsdots => 1 } ); .Ve .SS "Get the names of all files and subdirectories in a directory, recursively" .IX Subsection "Get the names of all files and subdirectories in a directory, recursively" .Vb 1 \& my @dirs_and_files = $f\->list_dir( \*(Aq/foo\*(Aq => { recurse => 1 } ); .Ve .SS "Do the same as above, but only to a certain maximum depth" .IX Subsection "Do the same as above, but only to a certain maximum depth" .Vb 2 \& my @dirs_and_files = \& $f\->list_dir( \*(Aq/foo\*(Aq => { recurse => 1, max_depth => 3 } ); .Ve .SS "Do the same, but ignore potential filesystem loops for a speed boost" .IX Subsection "Do the same, but ignore potential filesystem loops for a speed boost" .Vb 2 \& my @dirs_and_files = \& $f\->list_dir( \*(Aq/foo\*(Aq => { recurse_fast => 1, max_depth => 3 } ); .Ve .SS "Get the names of all files (no subdirectories) in a directory" .IX Subsection "Get the names of all files (no subdirectories) in a directory" .Vb 1 \& my @dirs_and_files = $f\->list_dir( \*(Aq/foo\*(Aq => { files_only => } ); .Ve .SS "Get the names of all subdirectories (no files) in a directory" .IX Subsection "Get the names of all subdirectories (no files) in a directory" .Vb 1 \& my @dirs_and_files = $f\->list_dir( \*(Aq/foo\*(Aq => { dirs_only => 1 } ); .Ve .SS "Get the number of files and subdirectories in a directory" .IX Subsection "Get the number of files and subdirectories in a directory" .Vb 3 \& my @dirs_and_files = $f\->list_dir( \& \*(Aq/foo\*(Aq => { no_fsdots => 1, count_only => 1 } \& ); .Ve .SS "Get the names of files and subdirs in a directory as separate array refs" .IX Subsection "Get the names of files and subdirs in a directory as separate array refs" .Vb 1 \& my( $dirs, $files ) = $f\->list_dir( \*(Aq/foo\*(Aq => { as_ref => 1 } ); \& \& \-OR\- \& \& my( $dirs, $files ) = $f\->list_dir( \& \*(Aq/foo\*(Aq => { dirs_as_ref => 1, files_as_ref => 1 } \& ); .Ve .SS "Load all the files in a directory into a hashref" .IX Subsection "Load all the files in a directory into a hashref" .Vb 1 \& my $templates = $f\->load_dir( \*(Aq/var/www/mysite/templates\*(Aq ); \& \& # $templates now contains something like: \& # { \& # \*(Aqheader.html\*(Aq => \*(Aq...file contents...\*(Aq, \& # \*(Aqbody.html\*(Aq => \*(Aq...file contents...\*(Aq, \& # \*(Aqfooter.html\*(Aq => \*(Aq...file contents...\*(Aq, \& # } \& \& print $templates\->{\*(Aqheader.html\*(Aq}; .Ve .SS "Recursively Get the names of all files that end in '.pl'" .IX Subsection "Recursively Get the names of all files that end in '.pl'" .Vb 3 \& my @perl_files = $f\->list_dir( \& \*(Aq/home/scripts\*(Aq => { files_match => qr/\e.pl$/, recurse => 1 } \& } .Ve .SS "Recursively get the names of all files that do \s-1NOT\s0 end in '.pl'" .IX Subsection "Recursively get the names of all files that do NOT end in '.pl'" File::Util's \f(CW\*(C`list_dir()\*(C'\fR method doesn't have a \*(L"not_matches\*(R" counterpart to the \*(L"files_match\*(R" parameter. This is because it doesn't need one. Perl already provides native support for negation in regular expressions. The example below shows you how to make sure a file does \s-1NOT\s0 match the pattern you provide as a subexpression in a \*(L"negative zero width assertion\*(R". .PP It might sound complicated for a beginner, but it's really not that hard. .PP See the perlre documentation for more about negation in regular expressions. .PP .Vb 4 \& # find all files that don\*(Aqt end in ".pl" \& my @other_files = $f\->list_dir( \& \*(Aq/home/scripts\*(Aq => { files_match => qr/^(?!.*\e.pl$)/, recurse => 1 } \& } .Ve .SS "Combine several options for \fBlist_dir()\fP and be awesome" .IX Subsection "Combine several options for list_dir() and be awesome" Find all files (not directories) that matches *any* number of given patterns (\s-1OR\s0), whose parent directory matches *every* pattern in a list of given patterns (\s-1AND\s0). Also make sure that the path to the files matches a list of patterns (\s-1AND\s0). .PP .Vb 11 \& # find the droids I\*(Aqm looking for... \& my @files = $f\->list_dir( \& \*(Aq/home/anakin\*(Aq => { \& files_match => { or => [ qr/droid/, qr/3p(o|O)$/i, qr/^R2/ }, \& parent_matches => { and => [ qr/vader/i, qr/darth/i ] }, \& path_matches => { and => [ qr/obi\-wan/i, qr/^(?!.*Qui\-Gon)/ ] }, \& recursive => 1, \& files_only => 1, \& max_depth => 8, \& } \& ); .Ve .PP The above example would find and return files like: .PP .Vb 3 \& /home/anakin/mentors/obi\-wan/villains/darth\-vader/R2.png \& /home/anakin/mentors/obi\-wan/villains/darth\-vader/C3P0.dict \& /home/anakin/mentors/obi\-wan/villains/darth\-vader/my_droids.list .Ve .PP But would not return files like: .PP .Vb 1 \& /home/anakin/mentors/Qui\-Gon Jinn/villains/darth\-vader/my_droids.list .Ve .SS "Use a callback to descend through (walk) a directory tree" .IX Subsection "Use a callback to descend through (walk) a directory tree" This is a really powerful feature. Because \fBFile::Util::list_dir()\fR is a higher order function, it can take other functions as arguments. We often refer to these as \*(L"callbacks\*(R". .PP Any time you specify a callback, File::Util will make sure it's first argument is the name if the directory it's in (recursion), and then the second and third arguments are listrefs. The first is a list reference containing the names of all subdirectories, and the second list ref contains the names of all the files. .PP Below is a very simple example that doesn't really do much other than demonstrate the syntax. You can see more full-blown examples of callbacks in the File::Util::Cookbook .PP .Vb 7 \& # print all subdirectories under /home/larry/ \& $f\->list_dir( \& \*(Aq/home/larry\*(Aq => { \& callback => sub { print shift @_, "\en" }, \& recurse => 1, \& } \& } .Ve .SS "Get a directory tree in a hierarchical hashref" .IX Subsection "Get a directory tree in a hierarchical hashref" .Vb 1 \& my $tree = $f\->list_dir( \*(Aq/tmp\*(Aq => { as_tree => 1, recurse => 1 } ); \& \& Gives you a datastructure like: \& { \& \*(Aq/\*(Aq => { \& \*(Aq_DIR_PARENT_\*(Aq => undef, \& \*(Aq_DIR_SELF_\*(Aq => \*(Aq/\*(Aq, \& \*(Aqtmp\*(Aq => { \& \*(Aq_DIR_PARENT_\*(Aq => \*(Aq/\*(Aq, \& \*(Aq_DIR_SELF_\*(Aq => \*(Aq/tmp\*(Aq, \& \*(AqhJMOsoGuEb\*(Aq => { \& \*(Aq_DIR_PARENT_\*(Aq => \*(Aq/tmp\*(Aq, \& \*(Aq_DIR_SELF_\*(Aq => \*(Aq/tmp/hJMOsoGuEb\*(Aq, \& \*(Aqa.txt\*(Aq => \*(Aq/tmp/hJMOsoGuEb/a.txt\*(Aq, \& \*(Aqb.log\*(Aq => \*(Aq/tmp/hJMOsoGuEb/b.log\*(Aq, \& \*(Aqc.ini\*(Aq => \*(Aq/tmp/hJMOsoGuEb/c.ini\*(Aq, \& \*(Aqd.bat\*(Aq => \*(Aq/tmp/hJMOsoGuEb/d.bat\*(Aq, \& \*(Aqe.sh\*(Aq => \*(Aq/tmp/hJMOsoGuEb/e.sh\*(Aq, \& \*(Aqf.conf\*(Aq => \*(Aq/tmp/hJMOsoGuEb/f.conf\*(Aq, \& \*(Aqg.bin\*(Aq => \*(Aq/tmp/hJMOsoGuEb/g.bin\*(Aq, \& \*(Aqh.rc\*(Aq => \*(Aq/tmp/hJMOsoGuEb/h.rc\*(Aq, \& } \& } \& } \& } .Ve .PP *You can add the \f(CW\*(C`dirmeta\*(C'\fR option, set to 0 (false), to remove the special entries \f(CW\*(C`_DIR_PARENT_\*(C'\fR and \f(CW\*(C`_DIR_SELF_\*(C'\fR from each subdirectory branch. .PP Example: .PP .Vb 3 \& my $tree = $f\->list_dir( \& \*(Aq/tmp\*(Aq => { as_tree => 1, dirmeta => 0, recurse => 1 } \& ); .Ve .PP *You can still combine the \f(CW\*(C`as_tree\*(C'\fR option with other options, such as the regex pattern matching options covered above, or options like \f(CW\*(C`recurse\*(C'\fR, or \&\f(CW\*(C`files_only\*(C'\fR. .PP *You should be careful using this feature with very large directory trees, due to the memory it might consume. Memory usage is generally low, but will grow when you use this feature for larger and larger directory trees. Bear in mind that the \f(CW$ABORT_DEPTH\fR limit applies here too (see File::Util documentation), which you can override manually by setting the \f(CW\*(C`abort_depth\*(C'\fR option: .PP .Vb 2 \& # set max recursion limit to an integer value as shown below \& $f\->list_dir( \*(Aq/tmp\*(Aq => { as_tree => 1, recurse => 1, abort_depth => 123 } ); .Ve .SS "Determine if something is a valid file name" .IX Subsection "Determine if something is a valid file name" \&\s-1NOTE:\s0 This method is for determining if a \fBfile name\fR is valid. It does not determine if a full path is valid. .PP .Vb 1 \& print $f\->valid_filename( \*(Aqfoo?+/bar~@/#baz.txt\*(Aq ) ? \*(Aqok\*(Aq : \*(Aqbad\*(Aq; \& \& \-OR\- \& \& print File::Util\->valid_filename( \*(Aqfoo?+/bar~@/#baz.txt\*(Aq ) ? \*(Aqok\*(Aq : \*(Aqbad\*(Aq; .Ve .PP Like many other methods in File::Util, you can import this into your own namespace so you can call it like any other function, avoid the object-oriented syntax when you don't want or need it: (This manual doesn't duplicate the main documentation by telling you every method you can import \*(-- see the \f(CW@EXPORT_OK\fR section of the File::Util documentation) .PP .Vb 1 \& use File::Util qw( valid_filename ); \& \& if ( valid_filename( \*(Aqfoo?+/bar~@/#baz.txt\*(Aq ) ) \& { \& print \*(Aqfile name is valid\*(Aq; \& } \& else \& { \& print \*(AqThat file name contains illegal characters\*(Aq; \& } .Ve .SS "Get the number of lines in a file" .IX Subsection "Get the number of lines in a file" .Vb 1 \& my $linecount = $f\->line_count( \*(Aqfoo.txt\*(Aq ); .Ve .SS "Split a file path into its parts" .IX Subsection "Split a file path into its parts" This method works differently than \fBatomize_path()\fR. With this method, you get not just the components of the path, but each element in the form of a list. The path will be split into the following pieces: (path root, if it exists, each subdirectory in the path, and the final file/directory ) .PP .Vb 1 \& use File::Util qw( split_path ); \& \& print "$_\en" for split_path( q{C:\efoo\ebar\ebaz\eflarp.pl} ) \& \& \-OR\- \& \& print "$_\en" for $f\->split_path( q{C:\efoo\ebar\ebaz\eflarp.pl} ) \& \& \-OR\- \& \& print "$_\en" for File::Util\->split_path( q{C:\efoo\ebar\ebaz\eflarp.pl} ) \& \& The output of all of the above commands is: \& C:\e \& foo \& bar \& baz \& flarp.pl .Ve .PP Above you see examples working on Windows-type paths. Below are some examples using *nix\-style paths: .PP .Vb 1 \& print "$_\en" for split_path( \*(Aq/I/am/your/father/NOOOO\*(Aq ) \& \& The output of all of the above commands is: \& / \& I \& am \& your \& father \& NOOOO .Ve .SS "Strip the path from a file name" .IX Subsection "Strip the path from a file name" .Vb 3 \& # On Windows \& # (prints "hosts") \& my $path = $f\->strip_path( \*(AqC:\eWINDOWS\esystem32\edrivers\eetc\ehosts\*(Aq ); \& \& # On Linux/Unix \& # (prints "perl") \& print $f\->strip_path( \*(Aq/usr/bin/perl\*(Aq ); \& \& # On a Mac \& # (prints "baz") \& print $f\->strip_path( \*(Aqfoo:bar:baz\*(Aq ); \& \& \-OR\- \& \& use File::Util qw( strip_path ); \& \& print strip_path( \*(Aq/some/file/name\*(Aq ); # prints "name" .Ve .SS "Get the path preceding a file name" .IX Subsection "Get the path preceding a file name" .Vb 3 \& # On Windows \& # (prints "C:\eWINDOWS\esystem32\edrivers\eetc") \& my $path = $f\->return_path( \*(AqC:\eWINDOWS\esystem32\edrivers\eetc\ehosts\*(Aq ); \& \& # On Linux/Unix \& # (prints "/usr/bin") \& print $f\->return_path( \*(Aq/usr/bin/perl\*(Aq ); \& \& # On a (very, very old) Mac \& # (prints "foo:bar") \& print $f\->return_path( \*(Aqfoo:bar:baz\*(Aq ); .Ve .SS "Find out if the host system can use flock" .IX Subsection "Find out if the host system can use flock" .Vb 2 \& use File::Util qw( can_flock ); \& print can_flock; \& \& \-OR\- \& \& print File::Util\->can_flock; \& \& \-OR\- \& \& print $f\->can_flock; .Ve .SS "Find out if the host system needs to call binmode on binary files" .IX Subsection "Find out if the host system needs to call binmode on binary files" .Vb 2 \& use File::Util qw( needs_binmode ); \& print needs_binmode; \& \& \-OR\- \& \& print File::Util\->needs_binmode; \& \& \-OR\- \& \& print $f\->needs_binmode; .Ve .SS "Find out if a file can be opened for read (based on file permissions)" .IX Subsection "Find out if a file can be opened for read (based on file permissions)" .Vb 1 \& my $is_readable = $f\->is_readable( \*(Aqfoo.txt\*(Aq ); .Ve .SS "Find out if a file can be opened for write (based on file permissions)" .IX Subsection "Find out if a file can be opened for write (based on file permissions)" .Vb 1 \& my $is_writable = $f\->is_writable( \*(Aqfoo.txt\*(Aq ); .Ve .SS "Escape illegal characters in a potential file name (and its path)" .IX Subsection "Escape illegal characters in a potential file name (and its path)" .Vb 2 \& # prints "C_\|_WINDOWS_system32_drivers_etc_hosts" \& print $f\->escape_filename( \*(AqC:\eWINDOWS\esystem32\edrivers\eetc\ehosts\*(Aq ); \& \& # prints "baz)_\|_@^" \& # (strips the file path from the file name, then escapes it \& print $f\->escape_filename( \*(Aq/foo/bar/baz)?*@^\*(Aq => { strip_path => 1 } ); \& \& # prints "_foo_!_@so~me#illegal$_file&(name" \& # (yes, technically that is a legal filename) \& print $f\->escape_filename( q{\efoo*!_@so~me#illegal$*file&(name} ); .Ve .SS "Find out if the host system uses \s-1EBCDIC\s0" .IX Subsection "Find out if the host system uses EBCDIC" .Vb 2 \& use File::Util qw( ebcdic ); \& print ebcdic; \& \& \-OR\- \& \& print File::Util\->ebcdic; \& \& \-OR\- \& \& print $f\->ebcdic; .Ve .SS "Get the type(s) of an existent file" .IX Subsection "Get the type(s) of an existent file" .Vb 2 \& use File::Util qw( file_type ); \& print file_type( \*(Aqfoo.exe\*(Aq ); \& \& \-OR\- \& \& print File::Util\->file_type( \*(Aqbar.txt\*(Aq ); \& \& \-OR\- \& \& print $f\->file_type( \*(Aq/dev/null\*(Aq ); .Ve .SS "Get the bitmask of an existent file" .IX Subsection "Get the bitmask of an existent file" .Vb 2 \& use File::Util qw( bitmask ); \& print bitmask( \*(Aq/usr/sbin/sendmail\*(Aq ); \& \& \-OR\- \& \& print File::Util\->bitmask( \*(AqC:\eCOMMAND.COM\*(Aq ); \& \& \-OR\- \& \& print $f\->bitmask( \*(Aq/dev/null\*(Aq ); .Ve .SS "Get time of creation for a file" .IX Subsection "Get time of creation for a file" .Vb 2 \& use File::Util qw( created ); \& print scalar localtime created( \*(Aq/usr/bin/exim\*(Aq ); \& \& \-OR\- \& \& print scalar localtime File::Util\->created( \*(AqC:\eCOMMAND.COM\*(Aq ); \& \& \-OR\- \& \& print scalar localtime $f\->created( \*(Aq/bin/less\*(Aq ); .Ve .SS "Get the last access time for a file" .IX Subsection "Get the last access time for a file" .Vb 2 \& use File::Util qw( last_access ); \& print scalar localtime last_access( \*(Aq/usr/bin/exim\*(Aq ); \& \& \-OR\- \& \& print scalar localtime File::Util\->last_access( \*(AqC:\eCOMMAND.COM\*(Aq ); \& \& \-OR\- \& \& print scalar localtime $f\->last_access( \*(Aq/bin/less\*(Aq ); .Ve .SS "Get the inode change time for a file" .IX Subsection "Get the inode change time for a file" .Vb 2 \& use File::Util qw( last_changed ); \& print scalar localtime last_changed( \*(Aq/usr/bin/vim\*(Aq ); \& \& \-OR\- \& \& print scalar localtime File::Util\->last_changed( \*(AqC:\eCOMMAND.COM\*(Aq ); \& \& \-OR\- \& \& print scalar localtime $f\->last_changed( \*(Aq/bin/cpio\*(Aq ); .Ve .SS "Get the last modified time for a file" .IX Subsection "Get the last modified time for a file" .Vb 2 \& use File::Util qw( last_modified ); \& print scalar localtime last_modified( \*(Aq/usr/bin/exim\*(Aq ); \& \& \-OR\- \& \& print scalar localtime File::Util\->last_modified( \*(AqC:\eCOMMAND.COM\*(Aq ); \& \& \-OR\- \& \& print scalar localtime $f\->last_modified( \*(Aq/bin/less\*(Aq ); .Ve .SS "Make a new directory, recursively if necessary" .IX Subsection "Make a new directory, recursively if necessary" .Vb 1 \& $f\->make_dir( \*(Aq/var/tmp/tempfiles/foo/bar/\*(Aq ); \& \& # you can optionally specify a bitmask for the new directory. \& # the bitmask is combined with the user\*(Aqs current umask for the creation \& # mode of the directory. (You should usually omit this.) \& \& $f\->make_dir( \*(Aq/var/tmp/tempfiles/foo/bar/\*(Aq, 0755 ); .Ve .SS "Touch a file" .IX Subsection "Touch a file" .Vb 2 \& use File::Util qw( touch ); \& touch( \*(Aqsomefile.txt\*(Aq ); \& \& \-OR\- \& \& $f\->touch( \*(Aq/foo/bar/baz.tmp\*(Aq ); .Ve .SS "Truncate a file" .IX Subsection "Truncate a file" .Vb 1 \& $f\->trunc( \*(Aq/wibble/wombat/noot.tmp\*(Aq ); .Ve .SS "Get the correct path separator for the host system" .IX Subsection "Get the correct path separator for the host system" .Vb 2 \& use File::Util qw( SL ); \& print SL; \& \& \-OR\- \& \& print File::Util\->SL; \& \& \-OR\- \& \& print $f\->SL; .Ve .SS "Get the correct newline character for the host system" .IX Subsection "Get the correct newline character for the host system" .Vb 1 \& use File::Util qw( NL ); \& \& print NL; \& \& \-OR\- \& \& print File::Util\->NL; \& \& \-OR\- \& \& print $f\->NL; .Ve .SS "Choose what to do if there's a problem (die, warn, zero, undefined, subref)" .IX Subsection "Choose what to do if there's a problem (die, warn, zero, undefined, subref)" .Vb 1 \& # When doing things with IO that might fail, set up good error handlers \& \& # "Fail, these examples will..." \& \& # If this call fails, die with an error message (*default*) \& $f\->write_file( \*(Aqbobafett.txt\*(Aq => $content => { onfail => \*(Aqdie\*(Aq } ); \& \& # If this call fails, issue a warning to STDERR, but don\*(Aqt die/exit \& $f\->list_dir( \*(Aq/home/greivous\*(Aq => { onfail => \*(Aqwarn\*(Aq } ); \& \& # If this call fails, return a zero value (0), and don\*(Aqt die/exit \& $f\->open_handle( \*(Aq/home/ventress/.emacs\*(Aq => { onfail => \*(Aqzero\*(Aq } ); \& \& # If this call fails, return undef, and don\*(Aqt die/exit \& $f\->load_file( \*(Aq/home/vader/darkside.manual\*(Aq => { onfail => \*(Aqundefined\*(Aq } ); \& \& # If this call fails, execute the subroutine code and do whatever it says \& # This code tries to load one directory, and failing that, loads another \& $f\->load_dir( \*(Aq/home/palpatine/lofty_plans/\*(Aq => { \& onfail => sub { return $f\->load_dir( \*(Aq/home/sidious/evil_plots/\*(Aq ) } \& } \& ); .Ve .SH "AUTHORS" .IX Header "AUTHORS" Tommy Butler .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright(C) 2001\-2013, Tommy Butler. All rights reserved. .SH "LICENSE" .IX Header "LICENSE" This library is free software, you may redistribute it and/or modify it under the same terms as Perl itself. For more details, see the full text of the \s-1LICENSE\s0 file that is included in this distribution. .SH "LIMITATION OF WARRANTY" .IX Header "LIMITATION OF WARRANTY" This software is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. .SH "SEE ALSO" .IX Header "SEE ALSO" File::Util::Manual, File::Util::Cookbook