#! /usr/bin/ksh93 # # Author: Mike Fleming mike@tauzero.co.uk # # Lists files containing a particular string, or with directory entries # containing a particular string, optionally with a particular file # extension. File contents can be viewed using more or fv. # # The special literal "today" or "today-n" where n is a number can be # used to indicate file names containing today's date or a date n days # in the past. By default the form ccyymmdd will be used - the -y option # specifies that the short yymmdd form is to be used. # # As well as a number, N for next, P for previous, and Q to quit, if # ! is input, a shell command can be executed - it can either be supplied # after ! (eg. !ls -l) or, if it is not supplied there, it will be # requested. # # Usage: # lookfor [-c] [-d] [-e] [-f] [-s] [-v] [-y] [-h] string [ filelist ] # # Options: # -c Case sensitive search - also affects case sensitivity in 'more' # -d Only search devel (not live) if in a devel directory # -e Expression search # -f Search for string in directory entries (eg. owner) # -s Specify a separator for date fields (eg. -s- format 2015-11-01) # -v View using fv (requires fv) # -y Use short date (yymmdd) for "today-n" date form # -h Help # # Note the scope for customisation with the two sections marked as site # specific parts PGLEN=25 CASE=-i EXP=-F DEVONLY=N YR=Y DS="" YRFLAG="" DSFLAG="" FILEENTRY=N VIEWER=more VCASE=-i ####### Site specific part (1) ################################################ # This is for if we want to search specific file types in specific # directories typeset -A flist # Set up a series of array elements, each containing the basename # of a directory and the extensions to be searched in that directory, # plus any other directories to be searched (eg. you might want to # search in live directories if you're looking in development ones). flist[sapsrc]='*.cbl *.CBL' flist[sapcpy]='*.cpy *.CPY *.SEL *.FD *.FS *.DEC *.88 *.99 *.LNK *.WS *.LIB ' flist[sapcpy]=${flist[sapcpy]}'*.PD' flist[sapshell]='*.ksh *.sh' ####### End of site specific part (1) ######################################### USAGE="Usage:\n lookfor [-c] [-d] [-e] [-f] [-s char] [-v] [-y] [-h] string [ filelist ]\n\n \t-c\tCase sensitive search (also affects behaviour of 'more')\n \t-d\tOnly search /devel if in a /devel directory\n \t-e\tExpression search\n \t-f\tFile entry search\n \t-s\tDate separator\n \t-v\tUse fv to view file\n \t-y\tUse short date (yymmdd) for 'today-n' date form\n \t-h\tHelp\n" HELP="\nLists files containing a particular string, or with directory entries containing a particular string, optionally with a particular file extension. File contents can be viewed by selecting from the displayed list. For certain directories, the filelist is automatically selected unless it is specifically provided:\n\n" HELP=$HELP$(for a in ${!flist[*]};do echo "$a\t${flist[$a]}"; done)"\n\n" HELP=$HELP"When in a dev directory, the corresponding live directory will also be searched unless either the -d flag is specified or the filelist is specifically provided.\n The special literal 'today' or 'today-n' where n is a number can be used to indicate file names containing today's date or a date n days in the past. By default the form ccyymmdd will be used - the -y option specifies that the short yymmdd form is to be used and the -s option allows a date separator character to be specified.\n Searches will by default be case insensitive - the -c option allows them to be made case sensitive. The case sensitivity of the search will be reflected in the case sensitivity of searches when executing the 'more' command.\n $USAGE" while getopts :cdefs:vyh opt do case $opt in c) CASE="" VCASE="";; d) DEVONLY="Y";; e) EXP="";; f) FILEENTRY=Y;; s) DS=$OPTARG DSFLAG="-s $OPTARG";; v) VIEWER=fv VCASE="";; y) YR=y YRFLAG=-y;; h) echo "$HELP" return;; ?) echo "Unknown option $OPTARG" echo "$USAGE" return 1;; :) echo "Missing value for $OPTARG" echo "$USAGE" return 1;; *) echo "$USAGE" return 1;; esac done shift $((OPTIND - 1)) if [[ -z "$1" ]] then echo $USAGE return 1 fi str=$1 shift ####### Site specific part (2) ################################################ # If we want to search live directories as well as development ones # If we're going to be looking in live as well as development # directories, set them up here in LSRC, LCPY, LSHELL # If they're reached via symlinks, get directories that symlinks point to if ls -ld $LIVESRC | grep '[-]>' >/dev/null then LSRC=$(ls -ld $LIVESRC | sed -e 's/.* -> //') else LSRC=$LIVESRC fi if ls -ld $LIVECPY | grep '[-]>' >/dev/null then LCPY=$(ls -ld $LIVECPY | sed -e 's/.* -> //') else LCPY=$LIVECPY fi if ls -ld $LIVESHELL | grep '[-]>' >/dev/null then LSHELL=$(ls -ld $LIVESHELL | sed -e 's/.* -> //') else LSHELL=$LIVESHELL fi # Now add those directories, and the extensions we'll be looking through # in them, to the array entries if [[ "$DEVONLY" != "Y" ]] then flist[sapsrc]=${flist[sapsrc]}' '$LSRC'/*.cbl '$LSRC'/*.CBL' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.cpy '$LCPY'/*.CPY' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.SEL '$LCPY'/*.FD ' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.FS '$LCPY'/*.DEC ' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.88 '$LCPY'/*.99 ' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.LNK '$LCPY'/*.WS ' flist[sapcpy]=${flist[sapcpy]}' '$LCPY'/*.LIB' flist[sapshell]=${flist[sapshell]}' '$LSHELL'/*.ksh '$LSHELL'/*.sh' fi ####### End of site specific part (2) ######################################### if [ -z "$1" ] then FLIST=${flist[$(basename $PWD)]} if [[ "$FLIST" == "" ]] then FLIST="*" fi if [[ "$FILEENTRY" == "Y" ]] then set -A fnames $(for a in $FLIST; do ls -l $a 2>/dev/null | grep $CASE $EXP "$str" | awk '{print $NF}'; done) else set -A fnames $(grep $CASE $EXP -l "$str" $FLIST 2>/dev/null) fi else fl= for a in $* do if [[ $(echo $a | cut -c1-5) == today ]] then if [[ $a == today ]] then l=$(ls *$(date +%$YR$DS%m$DS%d)* 2>/dev/null) else dd=$(echo $a | cut -c7-) l=$(ls *$(prev_date $DSFLAG $YRFLAG $dd)* 2>/dev/null) fi elif [[ $a == yesterday ]] then l=$(ls *$(prev_date $DSFLAG $YRFLAG 1)* 2>/dev/null) else l=$(ls $a 2>/dev/null) fi if [[ ! -z "$l" ]] then fl="$fl$l " fi done if [[ -z "$fl" ]] then echo "No matching files found" return fi if [[ "$FILEENTRY" == "Y" ]] then set -A fnames $(for a in $fl; do ls -l $a 2>/dev/null | grep $CASE $EXP "$str" | awk '{print $NF}'; done) else set -A fnames $(grep $CASE $EXP -l "$str" $fl) fi fi if [[ -z "${fnames[0]}" ]] then echo "No matching files found" return fi # page = current page (starts at 0) # index = screen array pointer for display (starts at 0) # line = display line number (starts at 1) # ptr = pointer to file to display typeset -i page=0 typeset -i index typeset -i line typeset -i ptr while [[ "$REPLY" != "Q" && "$REPLY" != "q" ]] do lastline=$((PGLEN - 1)) line=1 index=$((page * lastline)) while [[ -n "${fnames[$index]}" && $line -le $lastline ]] do if (( line < 10 )) then lno=" "$line else lno=$line fi echo "$lno" ${fnames[$index]} index=$((index + 1)) line=$((line + 1)) done FURTHER="" if [[ -n "${fnames[$index]}" ]] then FURTHER=$FURTHER" [N]ext page," fi if (( page > 0 )) then FURTHER=$FURTHER" [P]revious," fi read REPLY?"No. of file to view,$FURTHER [Q]uit, ! - shell cmd: " if [[ "$REPLY" == "" ]] then REPLY="X" fi if (( $(echo $REPLY | grep -c "^[0-9]*$") > 0 )) then if (( REPLY > 0 && REPLY <= lastline )) then ptr=$(((page * lastline) + (REPLY - 1))) if [[ -n "${fnames[$ptr]}" ]] then $VIEWER $VCASE ${fnames[$ptr]} fi fi elif (( $(echo $REPLY | grep -c "^!") > 0 )) then CMD=$(echo $REPLY | cut -c 2-) if [[ "$CMD" == "" ]] then read CMD?"Command to execute: " fi if [[ "$CMD" != "" ]] then eval $CMD fi else case $REPLY in P | p) if (( page > 0 )) then page=$((page - 1)) fi;; N | n) if [[ -n "${fnames[$index]}" ]] then page=$((page + 1)) fi;; esac fi done