#!/usr/bin/perl # # wcls This script shows line counts for sorted files named on # the command line. # # Revision History # 1.0 Initial revision. 151227 # 1.1 Added license info. 180526 # # Written by Wayne Morrison, 151227. # # Copyright 2015-2018 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 require_order); # # Version information. # my $NAME = "wcls"; my $VERS = "$NAME version: 1.1"; ############################################################################ # # Options fields. # my %opts = (); # Options. # # Command line arguments. # my @opts = ( 'c', # Sort by status change time. 'f', # Turn off sorting. 't', # Sort by modification time. 'u', # Sort by last file access time. 'U', # Sort by file creation time. 'S', # Sort based on line count. 'r', # Reverse the order. 'T', # Give total count as well. 'Q', # Give total count only. 'h', # Give a help message. 'V', # Display the program version. ); my $accsort = 0; # -u option flag. my $creatsort = 0; # -U option flag. my $modsort = 0; # -t option flag. my $statsort = 0; # -c option flag. my $unsorted = 0; # -f option flag. my $revit = 0; # -r option flag. my $sizesort = 0; # -S option flag. my $total = 0; # -T option flag. my $totalonly = 0; # -Q option flag. ############################################################################ my @regfiles = (); # Regular files from user's list. my $flist = ''; # Files from command line. my $opts = ''; # User's options. ############################################################################ main(); exit(0); #----------------------------------------------------------------------------- # Routine: main() # sub main { $| = 1; # # Munch on the options and arguments. # optsandargs(); # # Build a list of files. # buildlist(); # # Get and display the file counts of each file in the list. # linecounts(); } #---------------------------------------------------------------------- # Routine: optsandargs() # # Purpose: Parse the command line for options and arguments. # sub optsandargs { # # Parse the options. # Getopt::Long::Configure("bundling"); GetOptions(\%opts,@opts) || usage(); # # Check for some immediate-action options. # usage() if(defined($opts{'h'})); version() if(defined($opts{'V'})); # # Initialize the option set for some options. # $opts = ''; $opts .= 'c' if(defined($opts{'c'})); $opts .= 't' if(defined($opts{'t'})); $opts .= 'u' if(defined($opts{'u'})); $opts .= 'U' if(defined($opts{'U'})); # # Set some option variables for non-ls options. # $sizesort = 1 if(defined($opts{'S'})); $revit = 1 if(defined($opts{'r'})); # # Check for total flags. # $total = 1 if(defined($opts{'T'})); $totalonly = 1 if(defined($opts{'Q'})); # # "Sort on size" means we can ignore other sorting. # if($sizesort) { $opts = ''; } # # Check for mutually exclusive options, and complain if they're there. # if($total && $totalonly) { print STDERR "$0: -T and -Q are mutually exclusive\n"; exit(4); } # # The -f option means we shouldn't sort at all. # if(defined($opts{'f'})) { $opts = ''; $revit = 0; $sizesort = 0; } # # Set up reverse sorting. If we're sorting on something other # than size, we'll add the -r option to the option list. # if($revit) { if(($opts ne '') || ($sizesort == 0)) { $opts .= 'r'; } } # # Ensure that we use the -d and -1 options. # $opts = "$opts -d1"; $opts = "-$opts" if($opts !~ /^ /); # # Build our list of filenames to examine. # for(my $ind = 0; $ind < @ARGV; $ind++) { $flist .= ' ' . $ARGV[$ind]; } } #---------------------------------------------------------------------- # Routine: buildlist() # # Purpose: Build a list of files whose line counts will be retrieved # and reported. The files will be in the order given by # ls and the user-specified options. # # Different file types will be handled in different ways: # # file type action # --------- ------ # regular file get the line count of the file # directory ignore (for now) # everything else ignore # sub buildlist { my @allfiles = (); # All files to list. my %linecnts = (); # Line counts for the listed files. @regfiles = (); # # Get a list of the files in the order required by the options. # open(FS, "ls $opts $flist |"); @allfiles = ; close(FS); # # Build a list of files as ordered by ls. # # This is also where we'll have hooks to deal with specific file types. # (Future use.) # foreach my $fn (@allfiles) { chomp $fn; if(-f $fn) { push @regfiles, $fn; } elsif(-d $fn) { } } } #---------------------------------------------------------------------- # Routine: linecounts() # # Purpose: Find and print the line counts for each file in the # list of sorted files. # sub linecounts { my @outlines = (); # Lines to display. my $totallines = 0; # Total number of lines. # # Build the lines to be displayed. # foreach my $fn (@regfiles) { my $ln; # Output from wc. my $linecnt; # Line count for listed files. my $out; # Formatted output line. # # Get the line count for this file. # $ln = `wc -l $fn`; # # Pull the line count from the wc output. # $ln =~ /^\s*(\d+)\s(.+)$/; $linecnt = $1; $out = sprintf("%9d\t%s", $linecnt, $fn); push @outlines, $out; $totallines += $linecnt; } # # Display the line counts for each file. We'll allow for # reverse sorts if -r was given. # if($sizesort) { if($revit) { @outlines = sort {$b <=> $a } @outlines; } else { @outlines = sort {$a <=> $b } @outlines; } } # # Display the line counts for each file. # if(! $totalonly) { foreach my $ln (@outlines) { print "$ln\n"; } } # # Display the line counts for each file. # if($total) { printf("\n%9d\ttotal lines\n", $totallines); } elsif($totalonly) { printf("%9d\ttotal lines\n", $totallines); } } #---------------------------------------------------------------------- # 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: wcls [options] \n"; print STDERR "\n"; print STDERR "\twhere [options] are:\n"; print STDERR "\t\t-c sort on time of last file-status change\n"; print STDERR "\t\t-f do not sort\n"; print STDERR "\t\t-t sort on time of last modification\n"; print STDERR "\t\t-u sort on time of last access\n"; print STDERR "\t\t-U sort on time of file creation\n"; print STDERR "\n"; print STDERR "\t\t-S sort on line counts"; print STDERR "\t\t-r reverse sorting\n"; print STDERR "\n"; print STDERR "\t\t-help\n"; print STDERR "\t\t-Version\n"; exit(0); } 1; ############################################################################## =pod =head1 NAME B - shows line counts for sorted files named on the command line. =head1 SYNOPSIS wcls [options] =head1 DESCRIPTION B shows line counts for files named on the command line. A line is defined as any number of characters followed by a newline character. B is a front-end for what is effectively a B/B pipeline. The B command performs the actual line counting. The B command provides file lists and some selection and sorting functionality. Without any options, B will alphabetize its list of files, since that is how B presents the files. Several file-selection options are pass-throughs from B to B. These allow selection capabilities provided by B to be available to B. These options are I<-c>, I<-f>, I<-t>, I<-u>, and I<-U>. Any precedence or overrides among these options are determined by B. The B command has two file-sorting options whose functionality is provided directly by B. The functionality is implemented in B, but it matches (in character) the functionality of the B options. These are the I<-S> and I<-r> options. =head1 OPTIONS B takes the following options: =over 4 =item I<-c> This option sorts the files based on the last time the files' status changed. This option is a pass-through to B. =item I<-f> This option turns off sorting. This option is a pass-through to B. =item I<-t> This option sorts the files based on the time of last file modification. This option is a pass-through to B. =item I<-u> This option sorts the files based on the time of last file access. This option is a pass-through to B. =item I<-U> This option sorts the files based on the time of file creation. This option is a pass-through to B. =item I<-S> This option sorts the output based on numeric line counts. =item I<-r> This option reverses the sorted output. This option is a pass-through to B if the I<-S> option was not also given. =item I<-T> This option prints a total of lines counted along with the line counts for each file. =item I<-Q> This option prints a total of lines counted without the line counts for each file. =item I<-Version> Display the version information for B. =item I<-help> Display a help message. =back =head1 AUTHOR Wayne Morrison, wayne@waynemorrison.com =head1 LICENSE Copyright 2015-2018 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 SEE ALSO B, B =cut