#!/usr/bin/env perl # # fsfiles This script creates a file of all filenames in a file system. # # usage: # fsfiles [options] ... # # Revision History # 1.0 Initial revision. 151121 # 1.1 Fixed usage message. 160101 # 1.2 Added -append and -findopts options. 160127 # 1.3 Added license info. 180616 # # Written by Wayne Morrison, 151121. # # Copyright 2015 Wayne Morrison # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use strict; use Getopt::Long qw(:config no_ignore_case_always); use File::Temp qw/ tempfile /; # # Version information. # my $NAME = "fsfiles"; my $VERS = "$NAME version: 1.3"; ############################################################################ # # Options fields. # my %opts = (); # Options. # # Command line arguments. # my @opts = ( 'append', # Append to existing outfile. 'findopts=s', # Options to pass to find. 'nosort', # Turn off sorting. 'noxdev', # Turn off -xdev. 'outfile=s', # Output file. 'verbose', # Give verbose output. 'help', # Give a help message. 'Version', # Display the program version. ); my $appendit = 0; # Append to existing outfile. my $newout = 0; # Zap the output file. my $findopts = ''; # User's options for find. my $sortlist = 1; # Sorting flag. my $verbose = 0; # Verbose flag. my $xdev = 1; # Use-xdev flag. my $DEFOUT = './z.files'; # Default output file. my $DEFHIER = '/'; # Default hierarchy to check. my $outfile; # Output file. my @hierarchies = (); # Hierarchies to list. ############################################################################ main(); exit(0); #----------------------------------------------------------------------------- # Routine: main() # sub main { $| = 1; # # Munch on the options and arguments. # optsandargs(); # # Check the output file. # checkout(); # # Make a list of files. # lister(); } #---------------------------------------------------------------------- # Routine: optsandargs() # # Purpose: Parse the command line for options and arguments. # sub optsandargs { # # Parse the options. # GetOptions(\%opts,@opts) || usage(); # # Check for some immediate-action options. # usage() if(defined($opts{'help'})); version() if(defined($opts{'Version'})); # # Pick up the other options. # $appendit = $opts{'append'}; $findopts = $opts{'findopts'}; $verbose = $opts{'verbose'}; $sortlist = defined($opts{'nosort'}) ? 0 : 1; $xdev = defined($opts{'noxdev'}) ? 0 : 1; $outfile = defined($opts{'outfile'}) ? $opts{'outfile'} : $DEFOUT; # # Use the default hierarchy if none were given on the command line. # If anything was given, we'll use those. # if(@ARGV == 0) { @hierarchies[0] = $DEFHIER; } else { @hierarchies = @ARGV; } } #---------------------------------------------------------------------- # Routine: checkout() # # Purpose: Check the output file is okay. # If the named output file already exists: # - it must be a regular file # - it must be writable # - delete its contents, if we aren't appending to it # If the named output file does not already exist: # - it must be able to be created # sub checkout { # # If an output file was specified, we'll ensure it's writable and # a regular file. # If it isn't, we'll assure the default output file can be created. # if(-e $outfile) { # # Ensure the output file is a regular file. # if(! -f $outfile) { print STDERR "output file \"$outfile\" must be a regular file\n"; exit(1); } # # Ensure the output file is writable. # if(! -w $outfile) { print STDERR "output file \"$outfile\" must be writable\n"; exit(1); } # # Truncate the output file, if we aren't appending to it. # if(! $appendit) { open(OUT,"> $outfile"); truncate OUT, 0; close(OUT); print "using existing output file \"$outfile\"\n" if($verbose); } else { print "appending to existing output file \"$outfile\"\n" if($verbose); } } else { # # Ensure the output file can be created. # if(open(OUT,"> $outfile") == 0) { print STDERR "unable to create output file \"$outfile\"\n"; exit(1); } close(OUT); print "using new output file \"$outfile\"\n" if($verbose); } } #---------------------------------------------------------------------- # Routine: lister() # # Purpose: Go through the specified hierarchies and build a list of # their files. Unless -nosort was given, the final list # will be sorted. # sub lister { my $xdevopt = ''; # -xdev option. # # Determine whether or not to use the xdev option, depending on # the presence or absence of the -noxdev option. # $xdevopt = '-xdev' if($xdev); # # Go through the list of hierarchies and save the list # of their files to the output file. # foreach my $hier (@hierarchies) { my $cmd = ''; # Command to execute. $cmd = "find $hier $xdevopt $findopts -print >> $outfile"; print "listing $hier\n" if($verbose); system($cmd); } # # Maybe sort the final list. # sorter() if($sortlist); } #---------------------------------------------------------------------- # Routine: sorter() # # Purpose: Sort the final list. # sub sorter { my $fh; # File handle (unused.) my $tfn; # Filename of temporary file. print "sorting $outfile\n" if($verbose); # # Get a temporary file for The Sorting. # ($fh, $tfn) = tempfile(); # # Sort the final list into the temporary file, then plop # the temporary file contents over top of the final list. # system("sort $outfile > $tfn"); system("cat $tfn > $outfile"); # # Delete the temporary file. # unlink($tfn); } #---------------------------------------------------------------------- # Routine: version() # # Purpose: Print the version number(s) and exit. # sub version { print STDERR "$VERS\n"; exit(0); } #---------------------------------------------------------------------- # Routine: usage() # # Purpose: Give usage message and exit. # sub usage { print STDERR "usage: fsfiles [options] ... \n"; print STDERR "\n"; print STDERR "\twhere [options] are:\n"; print STDERR "\t\t-append\n"; print STDERR "\t\t-findopts find-options\n"; print STDERR "\t\t-nosort\n"; print STDERR "\t\t-noxdev\n"; print STDERR "\t\t-outfile output-file\n"; print STDERR "\n"; print STDERR "\t\t-verbose\n"; print STDERR "\t\t-help\n"; print STDERR "\t\t-Version\n"; exit(0); } 1; ############################################################################## =pod =head1 NAME B - Create a file of all the filenames in a file system =head1 SYNOPSIS fsfiles [options] ... =head1 DESCRIPTION B creates a file list of all the filenames in a named file system. (It handles plain file hierarchies as well; the name came because it was originally written for use with file systems.) The file list may be sorted or unsorted, depending on the options given. If no file systems are given on the command line, then the root file system will be used. If any file systems were given, then their files will be included in the file list. By default, B does not cross file system boundaries. This may be changed by using the I<-noxdev> option. The files in the hierarchies on the hierarchy list will be written to an output file. The default file-list file is B<./fsfiles>. A different file may be specified with the I<-outfile> option. If the output file exists, it must be a regular file and be writable. If it doesn't exist, B must be able to create the file. The file list is built using the B command. Specific behaviors, such as whether or not symbolic links are followed, depends on how B behaves. The B execution can be fine-tuned by using the I<-findopts> option with B. The file list is sorted using the B command. Specific behaviors, such as sort ordering, depends on how B behaves. B is essentially a front-end to B and B. Complex invocations of either command might be better suited by using those commands directly. =head1 OPTIONS B takes the following options: =over 4 =item I<-append> This option instructs B to append to an existing output file. =item I<-findopts> This option provides a set of options that will be passed to B. These options must be valid B options; B does not validate them. If multiple options are to be given, or if options are given that require arguments, the entire set must be passed in quotes. For example, the following command will tell B to only list regular files in the current directory that are newer than a specified file: fsfiles . -findopts '-type f -newer last-list-time' =item I<-nosort> This option prevents B from sorting the output file. =item I<-noxdev> This option determines whether or not file system boundaries will be crossed. By default, B will pass the I<-xdev> option to the B command. If the I<-noxdev> option is given, then I<-xdev> will not be given to B. =item I<-outfile> This option specifies the name of the output file. =item I<-verbose> This option provides verbose output. =item I<-Version> Display the version information for B. =item I<-help> Display a help message. =back =head1 LICENSE Copyright 2015 Wayne Morrison Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =head1 AUTHOR Wayne Morrison, wayne@waynemorrison.com =head1 SEE ALSO B, B =cut