#!/usr/bin/env bash # # fnlen This script displays info on filename lengths. # # This script was originally written in Perl for a purpose that # has been lost in the depths of time. While working to learn # bash programming, I decided it might be useful to convert the # Perl version to bash. It might not be very useful for actual # use, but it helped in learning bash. There are undoubtedly # better ways this could be written, but this was primarily a # learning exercise. # # usage: # fnlen [options] ... # # Revision History # 1.0 Initial revision. 160222 # 1.1 Added license info. 180616 # # Written by Wayne Morrison, 160222. # # Copyright 2016 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. # # # Version information. # NAME="fnlen" VERS="$NAME version: 1.1" ############################################################################ callname="${0##*/}" # Name by which we were called. dirs=0 # Treat filenames as directories. lt=0 # Maximum length to show. gt=0 # Minimum length to show. verbose=0 # Verbose-output flag. maxlen=-1 # Length of longest filename. ############################################################################ #----------------------------------------------------------------------------- # Routine: main() # # Purpose: Do everything. # main () { # # Check for arguments. # optsandargs "$@" # # Get the names and their lengths. If the -d option was given, # we'll treat the names as directory names and list their contents. # if [ $dirs -eq 0 ]; then # # Collect the length data we need. # getnames # # Show the filenames and their lengths. # showlens else dircnt=$fncnt for ((ind=0; ind < $dircnt; ind += 1)) do dn=${dirlist[ind]} curdir=`pwd` # # Move into this directory. # cd $dn 2>/dev/null if [ $? -ne 0 ] ; then vprint $dn is not a directory continue fi printf "$dn:\n" # # Initialize a few data. # unset files namelens maxlen=-1 # # Collect the length data we need. # getnames # # Show the filenames and their lengths. # showlens # # Return to our starting directory. # cd $curdir printf "\n" done fi } #----------------------------------------------------------------------------- # Routine: optsandargs() # # Purpose: Handle the command-line options. # optsandargs () { # # Set flags for each selected option. # while getopts ":l:g:dVvmh" opt; do case $opt in l ) lt=$OPTARG ;; g ) gt=$OPTARG ;; d ) dirs=1 ;; V ) version ;; v ) verbose=1 ;; m ) manpage ;; h ) usage 0 ;; \? ) usage 1 esac done # # Get rid of the arguments we've read. # shift $(($OPTIND - 1)) # # Get the list of files. It's okay if the list is empty. # oldifs=$IFS IFS=$'\n' fncnt=${#*} for ((ind=0; ind < $fncnt; ind += 1)) do if [ $dirs -eq 1 ]; then dirlist[$ind]=$1 else files[$ind]=$1 fi shift done IFS=$oldifs # # If the verbose flag was set, we'll show the parameters we'll use. # if [ $lt -lt $gt ]; then printf "$callname: maximum length ($lt) must be greater than minimum length ($gt)\n" exit 1 fi } #---------------------------------------------------------------------- # Routine: getnames() # # Purpose: Gather then name lengths for the given files. The name # lengths are saved in the namelens[] array. # getnames () { fncnt=${#files[*]} # Count of filenames. # # Get filenames from current directory if no filename # was given. # We're set if names were given on the command line. # if [ $fncnt -eq 0 ]; then # # Prevent space-based tokenization of filenames. # oldifs=$IFS IFS=$'\n' # # Get the files in this directory. # files=($(ls -1)) # # Add spaces and tab tokenization back to input. # IFS=$oldifs else # # The files array is already set up, so there's # nothing to do here. # : fi # # Save the lengths of the filenames into a parallel-indexed array. # We'll also save the largest filename length. # fncnt=${#files[*]} for ((ind=0; ind < $fncnt; ind += 1)) do # # Save the length of this filename. # len=${#files[ind]} namelens[ind]=$len # # Save the length if it's the greatest. # if [ $len -gt $maxlen ]; then maxlen=$len fi done } #---------------------------------------------------------------------- # Routine: showlens() # # Purpose: Display the filename lengths that have been gathered. # showlens () { fncnt=${#files[*]} if [ $fncnt -eq 0 ]; then printf "no filenames provided\n" exit 3 fi for ((ind=0; ind < $fncnt; ind += 1)) do printf "%d\t%-s\n" ${namelens[ind]} "${files[ind]}" done } #---------------------------------------------------------------------- # Routine: vprint() # # Purpose: Print the given string iff -verbose was given. # This is (currently) only used for error messages, so # the output goes to stderr. # vprint () { if [ $verbose -eq 1 ]; then printf "$*\n" 1>&2 fi } #---------------------------------------------------------------------- # Routine: version() # # Purpose: Print the version number(s) and exit. # version () { printf "$VERS\n" exit 0 } #---------------------------------------------------------------------- # Routine: usage() # # Purpose: Give usage message and exit. # usage () { ret=$1 printf "usage: fnlen [options] ... \n" printf "\n" printf "\twhere [options] are:\n" printf "\t\t-l maxlen show names less than this length\n" printf "\t\t-g minlen show names greater than this length\n" printf "\t\t-d treat listed names as directories\n" printf "\n" printf "\t\t-h display help message\n" printf "\t\t-m display man page\n" printf "\t\t-V display version information\n" exit $ret } ############################################################################## manstr=" NAME fnlen - displays info on filename lengths SYNOPSIS fnlen [options] ... DESCRIPTION fnlen displays the lengths of the filenames listed on the command line. If no filenames are listed, then the files in the current directory will be given. If the -d option is given, then the command-line arguments will be assumed to be the names of directories, and name lengths for the files in those directories will be given. This was written with the assumption that the arguments will be file names. However, those arguments can be any strings for which the user wants string lengths. OPTIONS fnlen takes the following options: -g minlen This option specifies the lower bound of the filename length. All names listed must be greater than this length. If the -g and -l options are both specified, then the -g length must be less than the -l length. -l maxlen This option specifies the upper bound of the filename length. All names listed must be less than this length. If the -g and -l options are both specified, then the -l length must be greater than the -l length. -d This option forces names listed to be interpreted as directory names. The files immediately within the listed directories will be listed. -V Display the version information for fnlen. -v Provide verbose error messages. -m Display this message. -h Display a help message. Copyright 2016 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. AUTHOR Wayne Morrison, wayne@waynemorrison.com NOTES This script was originally written in Perl for a purpose that has been lost in the depths of time. While working to learn bash, I decided it might be useful to convert the Perl version to bash. It might not be very useful for actual use, but it helped in learning bash programming. There are undoubtedly better ways this could be written, but this was primarily a learning exercise. " #---------------------------------------------------------------------- # Routine: manpage() # # Purpose: Print the manpage and exit. # manpage () { printf "$manstr\n" exit 0 } ############################################################################ # # Start things rolling. # main "$@" exit 0