#!/bin/ksh ## ## SCRIPT: findANDshow_stringINfile_plusminusNlines ## ## in $FEDIR/scripts where $FEDIR=/apps/nns_com/fea ## ############################################################################# ## PURPOSE: Let $1 $2 $3 represent the 3 positional arguments to this script -- ## . ## ## For the filename specified in $3, this script finds the lines in ## the file which contains a match to the string in $2 --- ## and it shows N lines above and below the 'match' lines, where ## N=$1. ## ## Like 'egrep', the string argument may be sub-strings separated ## by vertical-bars (|). Hence, the file can actually be searched ## for an OR-match, in any record of the file, to the several ## sub-strings within the string. ## ## Example string: 'fatal|error|fail|warning' ## ## 'awk' is used to find the match(es) and save-and-print the N lines ## above a match line as well as the N lines following, where N = $1. ## ## This is an 'egrep-like' utility --- except that it is an extended ## 'egrep' (one might say an 'eegrep') utility that shows lines ## around the match lines. This script does this with 'awk', ## because 'egrep' is not capable of showing the nearby lines. ############################################################################# ## CALL FORMAT: ## ## $FEDIR/scripts/findANDshow_stringINfile_plusminusNlines ## ## Can test with ## ./findANDshow_stringINfile_plusminusNlines 3 'tk|tool|DISPLAY' $HOME/test_eegrep ## ./findANDshow_stringINfile_plusminusNlines 2 'tk|tool|DISPLAY' $HOME/test_eegrep ## ./findANDshow_stringINfile_plusminusNlines 1 'tk|tool|DISPLAY' $HOME/test_eegrep ## ./findANDshow_stringINfile_plusminusNlines 0 'tk|tool|DISPLAY' $HOME/test_eegrep ## as well as ## ./findANDshow_stringINfile_plusminusNlines 6 'tk|tool|DISPLAY' $HOME/test_eegrep ## ./findANDshow_stringINfile_plusminusNlines 10 'tk|tool|DISPLAY' $HOME/test_eegrep ############################################################################# ## CALLED BY: the tk-GUI utility script shofil_ver2.tk ## in $FEDIR/tkGUIs ## ## and eventually in various FEA/CAE/CAD/Viz utility shell-scripts, like ## ## $FEDIR/scripts/ddam_find_f06_errs_bygui ## ############################################################################# ## MAINTENANCE HISTORY: ## Written by : Blaise Montandon 07aug2001 Based on script ## 'egrep_like_awk_plusminusNlines' ## in $FEDIR/scripts ## which was based on ## 'grep_3lines_around' ## in $FEDIR/scripts ## which is called by 'grep3' in $FEDIR/scripts. ## Also, see /apps/nns_com/fea/Dscrtest/test_awk_like_egrep ## Last Update: Blaise Montandon 29jan2002 Add a description of the '|' ## search option, at bottom of report. ## Last Update: Blaise Montandon 28oct2002 Add 'cut -c1-3071 $FILEin |' before ## awk, to avoid 'Input record too long' ## error that stops awk dead. ## ## Last Update: Blaise Montandon 21feb2003 Add '> $ERR_FILE' to several 'echo' ## statements, with ## ERR_FILE="/dev/console". ## This is to avoid a problem in ## overlaying the input file ($3), ## when $2 is '>' in the 3 input args ## $1 $2 $3. ## ## Last Update: Blaise Montandon 21feb2003 Use 'shift' and '$1' (and 'eval') ## logic to get the 3 input variables. ## This allows us to hide special characters like ## '>', in the 2nd var, from interpretation by the shell. ## ## Last Update: Blaise Montandon 21feb2003 Chg 'if ( UPPER ~ subSTRING[i] )' ## to 'if ( index(UPPER,subSTRING[i]) != 0 )' ## to avoid errors when subSTRING[i] is a ## special character like '?' or '>'. ## ## Last Update: Blaise Montandon 27may2003 Use $ALLinput to show all input ## in err msg. ## ## Last Update: Blaise Montandon 15dec2004 Add 'xpg' info to the trailer msg. ############################################################################# ERR_FILE="/dev/console" # ERR_FILE=`tty` ############################################################################# ## Save input, for err msg below. ############################################################################# ALLinput="$*" ## FOR TESTING: # echo " # ALLinput: $ALLinput" > $ERR_FILE ############################################################################# ## Get input items #1 and #2 and #3 from one string of input. ############################################################################# ## Based on the following '$1' and 'shift' example, ## from /apps/ideas_9/bin/msplot, ## which preserves any arguments in quotations: ## ## while test "$1" != "" ## SDI_ARGS="$SDI_ARGS \"$1\"" ## shift ## done ############################################################################# Nlines="$1" ## FOR TESTING: # echo " # Nlines: $Nlines" > $ERR_FILE shift ################################################################### ## Use 'eval' to remove single-quotes that protect the string from ## interpretation by the shell. Now the string can be special ## characters like '>'. #################################################################### # eval STRINGin=$1 ## seems to work OK. But let's try double-quotes around $1. #################################################################### eval STRINGin="$1" #################################################################### ## Change "\" to "\\" --- to avoid awk err msg ## 'Newline in string ... at source line 1' #################################################################### if test "$STRINGin" = '\' then STRINGin='\\' fi ## FOR TESTING: # echo " # STRINGin: $STRINGin" > $ERR_FILE shift FILEin="$1" ## FOR TESTING: # echo " # FILEin: $FILEin" > $ERR_FILE ############################################################################# ## Check for input item #1 and #2 and #3. ############################################################################# ERRMSG_MAIN="\ *********** INPUT ERROR: Supply an INTEGER and a STRING and a FILENAME to script $0. INPUT FORMAT: EXAMPLES: $0 3 'error' /var/adm/SYSLOG $0 3 'error|warning|core|dump' /var/adm/SYSLOG $0 3 'file systems' /var/adm/SYSLOG CURRENT INPUT: $ALLinput " if test "$Nlines" = "" then echo " $ERRMSG_MAIN Supply an INTEGER (plus-minus-Num-Lines) to script $0. Exiting ... " > $ERR_FILE exit fi if test "$STRINGin" = "" then echo " $ERRMSG_MAIN Supply a (search) STRING to script $0. Exiting ... " > $ERR_FILE exit fi if test "$FILEin" = "" then echo " $ERRMSG_MAIN Supply the FILENAME (of the file to search) to script $0. Exiting ... " > $ERR_FILE exit fi ############################################################################# ## Set scripts pathname in case this toolchest is not started from ## the nnsFEAmenu system --- and a $FEDIR utility script (or help) is needed. ############################################################################# if test "$FEDIR" = "" then FEDIR=/apps/nns_com/fea export FEDIR fi ######################################################################## ## PREPARE A REPORT FILE --- and its HEADING. ## (Put the lines in a local file whose name is built in $OUTLIST, ## by the 'set_localoutlist' utility.) ######################################################################## . $FEDIR/scripts/set_localoutlist echo " ********************* `date '+%Y %b %d %a %T%p %Z'` ****************** 'MATCH' LINES FROM FILE $FILEin Lines that contain the string '$STRINGin' (upper or lower case) --- INCLUDING $Nlines line(s) ABOVE-AND-BELOW 'match' lines. All lines are preceded by line numbers. An asterisk (*) before a line-number indicates a match, to the string, was found in the line. LineNumber:Text ---------------------------------------------------------------------------- " > $OUTLIST ############################################################################# ## CALL 'awk' -- with an appropriate awk program -- with file $3 as input. ## (Output is simply allowed to go to stdout. The calling utility script ## can direct stdout into an appropriate file.) ############################################################################# ## 'awk' program (AN EXAMPLE) to ## write all lines whose first field is different from the previous one. ## ## $1 != prev { print; prev = $1 } ## NOTE: ## This extended-egrep 'eegrep' script is basically ## a more complex version of this. ############################################################################# ################################################## ## FOR TESTING: ################################################## # TEST="YES" TEST="NO" if test "$TEST" = "YES" then echo " *.......................................................... * Lines in file $3 * that match the '|'-separated sub-strings in '$2' * --- including $1 line(s) above-and-below matches * --- are shown below. *.......................................................... * All lines are preceded by line numbers. * An asterisk (*) before a line-number indicates a match. *.......................................................... " > $ERR_FILE # set -x fi ################################################## ## HERE's the 'awk'. ################################################## ## Add 'cut -c1-3071 $FILEin |' before ## awk, to avoid 'Input record too long' ## error that stops awk dead. ################################################## cut -c1-3071 $FILEin | \ awk -v N="$Nlines" -v STRING="$STRINGin" \ 'BEGIN { ####################################################### ## Initialize the N "prev" vars to null. ## They are to hold the last N lines read. ####################################################### for ( i = 1 ; i <= N ; i++ ) { prev[i] = "" } ################################################## ## After converting STRING to upper-case, ## split the "STRING" into NS "subSTRING"s -- at ## occurrences of a vertical bar (|). ################################################## STRING=toupper(STRING) NS=split(STRING,subSTRING,"|") ## FOR TESTING: # print NS # print subSTRING[1] # print subSTRING[2] # print subSTRING[3] ################################################### ## "aftcount" holds the integer N,N-1,...,2,1, or 0 ## --- representing the number of lines after the ## last matched line that still need to be printed. ################################################### aftcount = 0 ###################################################### ## "lastprt" holds the line# of the line last printed. ## "lastprt" is reset any time "printf" is called. ###################################################### lastprt = 0 } #END OF BEGIN #START OF BODY { #################################################### ## IF WE HAVE A MATCH, SUSPEND PRINTING ## at N "AFTER-A-MATCH-LINES": ## If there is a new match, reset "aftcount" to zero. ## (We do not want to print a line twice.) ## We will restart aftcount at N after the new match ## line is printed. #################################################### ## We use "Match" to indicate whether there was a ## match to at least one of the subSTRINGs, in the ## current line ($0). Match==1 indicates a match. #################################################### Match = 0 UPPER=toupper($0) for ( i = 1 ; i <= NS ; i++ ) { # if ( UPPER ~ subSTRING[i] ) { aftcount = 0 ; Match = 1 } if ( index(UPPER,subSTRING[i]) != 0 ) { aftcount = 0 ; Match = 1 } ## FOR TESTING: # print "subSTRING LOOP:: " subSTRING[i] " aftcount: " aftcount " Match: " Match # # print "index(UPPER,subSTRING[i]): "index(UPPER,subSTRING[i]) } ## FOR TESTING: # }" $3 # exit ###################################################### ## PRINT ONE OF THE N "AFTER-A-MATCH-LINES": ## If "aftcount" is non-zero, print the current line. ## We had a match up to N lines ago. Decrement "aftcount" ## and save the number of the printed line in "lastprt". ###################################################### if ( aftcount != 0 ) { printf (" %s : %s \n", NR, $0); ## If this is the last of the "aftcount" lines, ## print a blank line. if ( aftcount == 1 ) {print ""} aftcount = aftcount - 1 ; lastprt = NR ## FOR TESTING: # print "aftcount != 0 CHECK:: aftcount: " aftcount " lastprt: " lastprt } ## FOR TESTING: # }" $3 # exit ###################################################### ## IF WE HAVE A MATCH, PRINT N-PREV & CURRENT: ## If there is a match, print the N previous lines ## --- as long as their linenums are greater than ## the last-printed line number. (We do not want ## to print a line twice.) ## ## Then print the current line. Also set "aftcount" ## to N, and save the ## number of the matched-printed line in "lastprt". ###################################################### for ( i = N ; i > 0 ; i-- ) { recnum = NR - i if ( Match == 1 && recnum > lastprt ) { printf (" %s : %s \n", recnum, prev[i]) } ## FOR TESTING: # print "prev[] PRINT-LOOP:: NR= " NR " recnum= " recnum " i= " i # print "prev[] PRINT-LOOP:: lastprt= " lastprt " prev[i]= " prev[i] } if ( Match == 1 ) { printf ("*%s : %s \n", NR, $0); aftcount = N; lastprt = NR ## FOR TESTING: # print "Match == 1 TEST:: aftcount: " aftcount " lastprt: " lastprt } ######################################################## ## Update prev[N], prev[N-1], ... , prev[2], and prev[1] ## before reading the next line. ######################################################## for ( i = N ; i > 1 ; i-- ) { prev[i] = prev[i-1] } prev[1] = $0 #END OF BODY }' >> $OUTLIST ## }' $FILEin >> $OUTLIST ######################################################################## ## ADD A TRAILER TO THE REPORT-FILE. ######################################################################## echo " ---------------------------------------------------------------------------- The report above was created by the script $0 The script uses an 'awk' program utility that essentially extends the capabilities of the 'egrep' (extended grep) program. 'egrep' can show the lines that contain matches to multiple strings, like 'fatal', 'error', 'fail', or 'warning'. But 'egrep' cannot show nearby lines. The 'awk' program used here essentially creates an extension of the 'egrep' utility. You could say this is an 'eegrep' utility. ---------------------------------------------------------------------------- THE 'VERTICAL-BAR' CHARACTER (|): In searching for multiple strings in lines of a file, you can feed 'egrep' the string 'fatal|error|fail|warning', where the strings are separated by the 'vertical-bar' character. The '|' character is 'shift-back-slash' on most keyboards. This 'findANDshow_stringINfile_plusminusNlines' utility accepts the '|' character. For example, to find all lines containing either 'memory' or 'source' (case-insensitive), use the search string 'memory|source'. ---------------------------------------------------------------------------- The script $0 is generally called from within the site 'xpg' text-file browse/extract/print utility, $FEDIR/scripts/xpg. If you cannot run 'xpg' by simply typing 'xpg' at a shell command prompt, you can make an alias for 'xpg' by putting the following in $HOME/.profile and logoff-logon to make the alias available in every window of a session. alias xpg='$FEDIR/scripts/xpg' Usage: xpg [-h] [-q] file1 [ file2 ... file8 ] --- You could also make an SGI desktop icon for the $FEDIR/scripts/xpg utility, and drop text files on it. --- The 'xpg' script actally calls the site Tcl-Tk GUI script $FEDIR/tkGUIs/shofil.tk ---------------------------------------------------------------------------- " >> $OUTLIST ######################################################################## ## SHOW THE REPORT-FILE OF ERR LINES FROM THE SELECTED PRINT FILE, $FILEIN. ######################################################################## $FEDIR/scripts/shofil $OUTLIST