#!/bin/sh ## ## SCRIPT: findANDshow_NOTstringsINfile.sh ## ## adapted from the 'FE xpg' subsystem of the Freedom Environment system, ## whose home page is at www.freedomenv.com. ## ## This is a 'stand-alone' version for contribution to wiki.tcl.tk ## ############################################################################# ## 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 DO NOT contain a match to the string(s) in $1. ## It uses a case-sensitive search, depending on whether $2 is ## 'yes' or 'no'. ## ## Like 'egrep', the string argument may be sub-strings separated ## by vertical-bars (|). Hence, the file can actually be searched ## for a NOT-AND-match, in any record of the file, to the several ## sub-strings within the string. ## ## Example string: 'fatal|error|fail|warning' ## ## NOTE: INCLUDING THE SINGLE QUOTES. They are needed to keep the ## shell from trying to execute the string, esp. when it ## contains special characters like < or > or [ or ] or ## parentheses or ! or whatever. ## ## 'awk' is used to find the NON-match(es) lines of the input file. ## ## This is an 'egrep-like' utility. It is like 'egrep -v' or ## 'egrep -i -v'. ## ## However, by using 'awk', we might extend this search someday to ## accept an Nlines integer input --- and then show plus-or-minus N lines ## around the NON-match lines. This script would do this with 'awk', ## because 'egrep' is not capable of showing the nearby lines. ############################################################################# ## CALL FORMAT: ## ## $DIRxpg/findANDshow_NOTstringsINfile.sh ## ############################################################################# ## CALLED BY: the tk-GUI utility script 'shofil.tk' ## ## to support the unique 'Show All Matches' productivity feature. ## ############################################################################# ## MAINTENANCE HISTORY for this 'stand-alone' version: ## ## Written: Blaise Montandon 2013aug05 Started work on creating this ## 'stand-alone' version from the ## 'integrated' 'FE xpg' subsystem at ## www.freedomenv.com. ## Updated: Blaise Montandon 20....... ############################################################################# THISscript="$0" THISscriptBASE=`basename "$THISscript"` ############################################################################# ## Save input, for err msg below. ############################################################################# ALLinput="$*" ## FOR TESTING: # echo " # ALLinput: $ALLinput" ############################################################################# ## Get input items #1 and #2 and #3 from one string of input. ############################################################################# ## Based on the following '$1' and 'shift' example, ## which preserves any arguments in quotations: ## ## while test "$1" != "" ## APP_ARGS="$APP_ARGS \"$1\"" ## shift ## done ############################################################################# ################################################################### ## 1) Get the first of 3 parms --- the parm. ################################################################### ## 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" shift CaseSense="$1" ## FOR TESTING: # echo " # CaseSense: $CaseSense" shift FILEin="$1" ## FOR TESTING: # echo " # FILEin: $FILEin" ############################################################################# ## Check for input item #1 and #2 and #3. ############################################################################# ERRMSG_MAIN="\ *********** INPUT ERROR: Supply 3 inputs --- a STRING and yes/no (CaseSense) and a FILENAME to script $THISscript. INPUT FORMAT: EXAMPLES: $THISscriptBASE 'error' no /var/adm/SYSLOG $THISscriptBASE 'error|warning|core|dump' no /var/adm/SYSLOG $THISscriptBASE 'file systems' yes /var/adm/SYSLOG CURRENT INPUT: $ALLinput " if test "$STRINGin" = "" then echo " $ERRMSG_MAIN Supply a (search) STRING to script $THISscript. Exiting ... " exit fi if test "$CaseSense" = "" then echo " $ERRMSG_MAIN Supply a Case-Sensitivity Indicator (yes/no) to script $THISscript. Exiting ... " exit fi if test "$FILEin" = "" then echo " $ERRMSG_MAIN Supply the FILENAME (of the file to search) to script $THISscript. Exiting ... " exit fi ############################################################################# ## Set DIRxpg for use in the 'stand-alone' version of the 'xpg' system. ############################################################################# # DIRxpg="$HOME/apps/xpg" DIRxpg="." ######################################################################## ## 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.) ######################################################################## ## This dot (.) is not needed. It just seem to be a little more efficient ## to not spawn off a new shell environment to run this script, if we ## do not need to do so. . $DIRxpg/set_localoutlist.sh CaseSenseMsg="(CASE-SENSITIVE)" if test "$CaseSense" = "no" then CaseSenseMsg="(upper or lower case ; that is, CASE-INSENSITIVE)" fi MULTICHECK=`echo "$STRINGin" | grep '|'` if test "$MULTICHECK" = "" then StringMsg="string" else StringMsg="any of the strings separated by '|' in " fi echo "\ ********************* `date '+%Y %b %d %a %T%p %Z'` ****************** 'NON-MATCH' LINES FROM FILE $FILEin Lines that DO NOT contain $StringMsg '$STRINGin' $CaseSenseMsg All lines are preceded by line numbers. LineNumber:Text ---------------------------------------------------------------------------- " > "$OUTLIST" ############################################################################# ## CALL 'awk' -- with an appropriate awk program -- with a file as input. ############################################################################# ## '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 example. ############################################################################# ################################################## ## FOR TESTING: ################################################## # TEST="YES" TEST="NO" if test "$TEST" = "YES" then echo " *.......................................................... * Lines in file $FILEin * that DO NOT match ANY of the '|'-separated sub-strings in * the string * '$STRINGin' * are shown below. *.......................................................... " # 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 (on SGI-IRIX). ################################################## cut -c1-3071 "$FILEin" | \ awk -v STRING="$STRINGin" -v CASESENSE="$CaseSense" \ 'BEGIN { ################################################## ## After converting STRING to upper-case, ## if CASESENSE=no, ## split the "STRING" into NS "subSTRING"s -- at ## occurrences of a vertical bar (|). ################################################## if ( CASESENSE == "no" ) { STRING = toupper(STRING) } NS=split(STRING,subSTRING,"|") ## FOR TESTING: # print "CASESENSE: " CASESENSE # print "NS: " NS # print "subSTRING[1] :" subSTRING[1] # print "subSTRING[2] :" subSTRING[2] # print "subSTRING[3] :" subSTRING[3] ###################################################### ## "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 ( CASESENSE == "no" ) { HOLDline = toupper($0) } else { HOLDline = $0 } ## FOR TESTING: # if ( NR < 10 ) { print "HOLDline :" $HOLDline } #################################################### ## We use "Match" to indicate whether there was a ## match to the subSTRINGs, in the current ## line ($0). Match==1 indicates a match to at least ## ONE the substrings, which means we do NOT print ## the line. We print the line if Match==0. #################################################### Match = 0 for ( i = 1 ; i <= NS ; i++ ) { if ( index(HOLDline,subSTRING[i]) != 0 ) { Match = 1 } ## FOR TESTING: # print "subSTRING LOOP - subSTRING[i]: " subSTRING[i] " Match: " Match # # print "index(HOLDline,subSTRING[i]): "index(HOLDline,subSTRING[i]) } ## FOR TESTING: # }" "$FILEin" # exit ###################################################### ## PRINT THE LINE if Match == 0 (none of the substrings ## had a match in the line). ###################################################### if ( Match == 0 ) { printf (" %s : %s \n", NR, $0); lastprt = NR ## FOR TESTING: # print "Match == 0 --- lastprt: " lastprt } ## FOR TESTING: # }" "$FILEin" # exit #END OF BODY }' >> "$OUTLIST" ## }' $FILEin >> "$OUTLIST" ######################################################################## ## ADD A TRAILER TO THE REPORT-FILE. ######################################################################## echo " ---------------------------------------------------------------------------- The report above was created by the utility script $THISscriptBASE The script uses an 'awk' program that shows all lines of an input file EXCEPT the lines which contain a match to at least one of *one-or-more* strings. Example: 'error', 'fail', 'fatal', or 'warning'. A multiple-strings argument is formed by separating the multiple strings by vertical-bars (|). Example: 'fatal|error|fail|warning' ---------------------------------------------------------------------------- As an example of how this 'NOT' search capability works, if you use the string '##' and search one of the scripts in any of the FE subsystems, you will see the script with most of the comment lines removed. ---------------------------------------------------------------------------- You can eliminate more comment lines by using the search string '##|# ' where there is a space character after the #-sign in the 2nd string. (The space character is helpful to avoid eliminating lines with a string like '#c0c0ff' which could be a hex string specifying a color for a GUI.) ---------------------------------------------------------------------------- And you can use the 'NOT' search capability following a search without 'NOT'. For example, if you want to see all the lines of a script that contain the string 'HOME', you could do a search without 'NOT'. Then, if that returned so many comment lines that the extraction-list was hard to read, apply a 'NOT' search, on that extraction list which is being shown in an 'xpg' window, using the string '##' . In the resulting 3rd 'xpg' window, you will find an extraction-list with mostly non-comment lines that contain the string 'HOME'. Alternatively, you can do the 'NOT' search FIRST, to get rid of most of the comment lines. And THEN do an 'xpg' search with string 'HOME', with the 'NOT' checkbutton turned OFF. ---------------------------------------------------------------------------- The script $THISscriptBASE is called from within the FE system 'xpg' text-file browse/extract/print utility. [Actually, the 'xpg' script calls the Tcl-Tk GUI script $DIRxpg/shofil.tk --- and it is this Tcl-Tk script that calls the script $THISscriptBASE.] --------------------------------------------------------------------------- If 'xpg' is 'not found' when you type 'xpg' at a shell command prompt, you can make an alias for 'xpg' by putting the following alias definition in your shell rc (run control) file --- such as $HOME/.bashrc or $HOME/.bash_aliases. alias xpg='$HOME/apps/bin/xpg' Then logoff-logon to make the alias available in every window of a login session. --- You could also make a desktop icon for the $HOME/apps/bin/xpg utility, and drop text files on it. --- If you type 'xpg', without an input filename, at a command prompt, you will see a usage hint like the following. Usage: xpg [-h] [-f] file1 [ file2 ... file8 ] I.e. xpg is setup to browse up to 8 files at a time. The limit is to help avoid accidentally opening up more xpg-windows than one wants to deal with. This can happen if you have an 'xpg' icon on your desktop and you unintentionally drag a sheet-load of filenames onto the icon. ********************* `date '+%Y %b %d %a %T%p %Z'` ****************** " >> "$OUTLIST" ######################################################################## ## SHOW THE REPORT-FILE OF ERR LINES FROM THE SELECTED PRINT FILE, $FILEIN. ######################################################################## $DIRxpg/xpg "$OUTLIST"