#!/bin/sh # @(#) /u/des/src/lsn/lsn 1.14 99/08/11 17:04:21 # # lsn -- list directory out in specifiable number of columns # # Copyright (c) 1998 by Daniel E. Singer. All rights reserved. # Permission is granted to reproduce and distribute this program # with the following conditions: # 1) This copyright notice and the author identification below # must be left intact in the program and in any copies. # 2) Any modifications to the program must be clearly identified # in the source file. # # Written by Daniel E. Singer, Duke Univ. Dept of Computer Science, 5/94 # # Modifications: # # 6/14/94, D.Singer # fixed awk problem, er, feature, by adding "+ 0"; # added "ls -F" compatibility, ie, not overwriting the special char; # added -w; # went from 'pr' for columns, to awk processing; # added -f; # 6/17/94, D.Singer # added separation between multiple dirs; # 6/20/94, D.Singer # added -v flag to 'cat' to cover screen glitch; # 3/21/96, D.Singer # fix for Solaris 'expr'; # 1/29/97, D.Singer # added -l; # fixed problem with command line wild cards; # 6/17/97, D.Singer # fixed problem with -l; # 5/13/98, D.Singer # fixed problems with expr; # fixed problems with FreeBSD; # changed default ls flags to AF; # 5/18/98, D.Singer # updated argument processing; # added -W; # some other house cleaning; # 6/10/99, D.Singer # more attempts to try to reconcile dir names with spaces and/or # wildcards; PATH='/usr/bin:/bin:/usr/ucb:/usr/bsd:/usr/sbin:/sbin:/usr/local/bin' export PATH LS="ls" TR="tr" WC="wc" AWK="awk" CAT="cat" SED="sed" EXPR="expr" MORE="more" UNAME="uname -sr" BASENAME="basename" SYS=`$UNAME` case "$SYS" in "SunOS "*) #EXPR="/usr/ucb/expr" AWK="nawk" esac DFLT_COLS=4 DFLT_SCR_WID=80 WIDE_SCR_WID=132 LS_FLAGS=" -AF" # flags to pass to LS PROG=`$BASENAME "$0"` USAGE=" Usage: $PROG [-#fhpw] [-l \"flags\"] [-W width] [dir...] -# specify number of columns, default is $DFLT_COLS; -f force output columns to maximum width; -h print help message and exit; -l flags to pass to 'ls', default is$LS_FLAGS; -p send the output through a display pager; -w wide display, $WIDE_SCR_WID characters, default is $DFLT_SCR_WID; -W specify screen width in characters; dir directory[s] to list, default is current directory; if using wildcards, the dir argument should be quoted; " SUMMARY=" '$PROG' will list directories out in a specifiable number of columns. This can be useful in situations where one or more long filenames cause the output of 'ls' to be in fewer columns than desired. " COLS="$DFLT_COLS" # output columns SCR_WID="$DFLT_SCR_WID" # screen width, characters PAGE=0 # send through pager FORCE=0 # force to max width: # this changes the output format slightly, and # avoids a sometimes missing last column due to # certain combinations of num-columns and num-entries FIRST=1 # first directory listed MULTI=0 # multiple directories : ${PAGER:=$MORE} # use environment setting if possible # # process command line options # colnum_error() { echo "$PROG: invalid column number." >&2 echo "$USAGE" >&2 exit 1 } scrwid_error() { echo "$PROG: invalid screen width." >&2 echo "$USAGE" >&2 exit 1 } syntax_error() { echo "$PROG: option syntax error." >&2 echo "$USAGE" >&2 exit 1 } arg_syntax_check() { [ "$1" -lt 1 ] && syntax_error } while [ "$#" -gt 0 ]; do OPT="$1" case "$OPT" in # options without argument -[1-9]|-[1-9][0-9]|-[1-9][0-9][0-9]) COLS=`$EXPR "$OPT" : '.\(.*\)'` ;; -f) FORCE=1 ;; -h) echo " *** `echo \"$PROG\" | $TR 'a-z' 'A-Z'` *** $SUMMARY$USAGE" exit 0 ;; -p) PAGE=1 ;; -w) SCR_WID="$WIDE_SCR_WID" ;; # options with argument -l) shift arg_syntax_check "$#" LS_FLAGS="$1" case "$LS_FLAGS" in -*) LS_FLAGS=" $LS_FLAGS" ;; *) LS_FLAGS=" -$LS_FLAGS" esac ;; -W) shift arg_syntax_check "$#" SCR_WID="$1" case "$SCR_WID" in [1-9]|[1-9][0-9]|[1-9][0-9][0-9]) ;; *) scrwid_error esac ;; # ... --) shift break ;; # unknown option -?) syntax_error ;; # don't want numbers starting with zero -0*) colnum_error ;; # need to do this to avoid an infinite loop -[0-9][0-9][0-9][0-9]*) colnum_error ;; # compound option -??*) # break up a compound option; # consecutive digits will become a single argument; NEW_OPTS=`$AWK 'BEGIN { OPT_STR = "'"$OPT"'"; LEN = length(OPT_STR); NEW_OPTS = ""; STATUS = 0; IN_NUM = 0; for (POS=2; POS+0 <= LEN; ++POS) { OPT = substr(OPT_STR,POS,1); if (OPT !~ /[a-zA-Z0-9_]/) STATUS = 1; if (IN_NUM && OPT ~ /[0-9]/) { NEW_OPTS = NEW_OPTS OPT; continue; } NEW_OPTS = NEW_OPTS " -" OPT; IN_NUM = (OPT ~ /[0-9]/); } print NEW_OPTS; exit STATUS; }' <&-` || { syntax_error } shift set -- $NEW_OPTS ${1:+"$@"} continue ;; # end of options, just command arguments left *) break esac shift done # # check number of arguments remaining # if [ "$#" = 0 ]; then # push current directory to positional param list set -- . elif [ "$#" -gt 1 ]; then MULTI=1 fi # # calc the width of a column # COL_WID=`$EXPR "$SCR_WID" / "$COLS" - 1` for DIR do # # escape any spaces or tabs in the DIR name that aren't already escaped; # not going to worry about newlines; # case "$DIR" in *[\ \ ]*) DIR=`echo "$DIR" | $AWK '{ S = $0; while (match(S,/[^\\\\][ ]/)) S = substr(S,1,RSTART) "\\\\" substr(S,RSTART+1); if (match(S,/^[ ]/)) S = "\\\\" S; print S; }'` esac #echo "DIR=\"$DIR\"" #continue case "$DIR" in */*) # strip of path components ENTRIES=`eval "$LS$LS_FLAGS $DIR" | $SED 's/\(.*\/\)\([^$]\)/\2/'` ;; *) ENTRIES=`eval "$LS$LS_FLAGS $DIR"` esac ENT_CNT=`echo "$ENTRIES" | $WC -l` # # if multiple dirs, precede each with its name # if [ "$MULTI" = 1 ]; then [ "$FIRST" = 0 ] && echo "" FIRST=0 echo "$DIR:" fi echo "$ENTRIES" | $AWK ' BEGIN { COLS = '"$COLS"'; # number of output columns COL_WID = '"$COL_WID"'; # width of output columns ENT_CNT = '"$ENT_CNT"'; # number of entries in dir FORCE = '"$FORCE"'; # force output format LINES = int((ENT_CNT + (COLS - 1)) / COLS); # number of lines F_PAT = "[/*@=]$"; # suffixes produces by "ls -F" NUM_ENTS = 0; # count of entries as read in } { # # make the entries, adjusting the size and suffix # LEN = length($0); if (LEN <= COL_WID) ENT[NUM_ENTS++] = $0; else { # long string: # truncate and add "%"; # preserve the file type indicator if ($0 ~ F_PAT) { DIFF = 2; TYPE = substr($0,LEN,1); } else { DIFF = 1; TYPE = ""; } ENT[NUM_ENTS++] = substr($0,1,COL_WID-DIFF) TYPE "%"; } } END { # # print out in tabular form # ++COL_WID; MOD = NUM_ENTS % COLS; # used with FORCE MOD2 = ((MOD == 0) ? COLS : MOD) + 0; # produce output by lines for (LINE=0; LINE < LINES; ++LINE) { TEXT = ""; for (COL=0; COL < COLS; ++COL) { # compute the index of the next entry # on the line if (FORCE == 1 && COL >= MOD2) { NUM = (COL >= MOD2 && LINE == LINES - 1) \ ? NUM_ENTS \ : (LINE + (COL * LINES)) - (COL - MOD); } else NUM = LINE + (COL * LINES); # add the entry to the current line, # with appropriate space padding TEXT = TEXT sprintf("%-"COL_WID"s",ENT[NUM]); } # get rid of spaces at end of line, # and print it sub(" *$","",TEXT); print TEXT; } }' done | if [ "$PAGE" = 1 ]; then $PAGER else $CAT -v fi exit