Script to report script functions defined and where called

Handy tool.

One proviso: for every function definition, of the form

thisFunction()

there must be a corresponding closing brace, of the form

}	# thisFunction()

Sample report without "--details":

 CALL to  promptForReferencePath          [selectOneOf]
 CALL to  purgeIdentical                  [reportAndPurge]
 CALL to  purgeIdentical                  [reportAndPurge]
 CALL to  purgeIdentical                  [reportAndPurge]
 CALL to  purgeIdentical                  [reportAndPurge]
 CALL to  diffFile                        [diffFile]
 CALL to  diffImg                         [diffFile]
 CALL to  diffVid                         [diffFile]
 CALL to  diffBin                         [diffFile]
 CALL to  diffFile                        [fils_NewerInReference]
 CALL to  closeMatchDiff                  [fils_NewerInReference]
 CALL to  closeMatchDiff                  [fils_NewerInReference]
 CALL to  closeMatchDiff                  [fils_NewerInReference]
 CALL to  closeMatchDiff                  [fils_NewerInReference]
 CALL to  reportAndPurge                  [fils_NewerInReference]
 CALL to  reportAndPurge                  [fils_NewerInReference]
 CALL to  diffFile                        [fils_NewerInCurrent]
 CALL to  closeMatchDiff                  [fils_NewerInCurrent]
 CALL to  closeMatchDiff                  [fils_NewerInCurrent]
 CALL to  closeMatchDiff                  [fils_NewerInCurrent]
 CALL to  closeMatchDiff                  [fils_NewerInCurrent]
 CALL to  reportAndPurge                  [fils_NewerInCurrent]
 CALL to  reportAndPurge                  [fils_NewerInCurrent]
 CALL to  dirs_NewerInReference           [evaluateDirs]
 CALL to  evaluateFils                    [evaluateDirs]
 CALL to  dirs_NewerInCurrent             [evaluateDirs]
 CALL to  fils_NewerInReference           [evaluateFils]
 CALL to  fils_NewerInCurrent             [evaluateFils]
 CALL to  diffFile                        [evaluateFils]
 CALL to  closeMatchDiff                  [evaluateFils]
 CALL to  closeMatchDiff                  [evaluateFils]
 CALL to  reportAndPurge                  [evaluateFils]
 CALL to  fils_NewerInReference           [evaluateFils]
 CALL to  fils_NewerInCurrent             [evaluateFils]
 CALL to  evaluateDirs                    [scanLibsLoop]
 CALL to  evaluateFils                    [scanLibsLoop]
 CALL to  promptForReferencePath          [MAIN]
 CALL to  scanLibsLoop                    [MAIN]
 CALL to  selectOneOf                     [MAIN]
 CALL to  scanLibsLoop                    [MAIN]
 CALL to  selectYesNo                     [MAIN]

Sample report with the "--details" option:

 Function  selectYesNo                     ->  funcName[1]
 Function  promptForReferencePath          ->  funcName[2]
 Function  selectOneOf                     ->  funcName[3]
 Function  dirs_NewerInReference           ->  funcName[4]
 Function  dirs_NewerInCurrent             ->  funcName[5]
 Function  purgeIdentical                  ->  funcName[6]
 Function  reportAndPurge                  ->  funcName[7]
 Function  diffImg                         ->  funcName[8]
 Function  diffVid                         ->  funcName[9]
 Function  diffBin                         ->  funcName[10]
 Function  closeMatchDiff                  ->  funcName[11]
 Function  diffFile                        ->  funcName[12]
 Function  fils_NewerInReference           ->  funcName[13]
 Function  fils_NewerInCurrent             ->  funcName[14]
 Function  evaluateDirs                    ->  funcName[15]
 Function  evaluateFils                    ->  funcName[16]
 Function  scanLibsLoop                    ->  funcName[17]

 DEFINE  selectYesNo ...
    END  selectYesNo .

 DEFINE  promptForReferencePath ...
    END  promptForReferencePath .

 DEFINE  selectOneOf ...
	  CALL to  promptForReferencePath          [selectOneOf]
    END  selectOneOf .

 DEFINE  dirs_NewerInReference ...
    END  dirs_NewerInReference .

 DEFINE  dirs_NewerInCurrent ...
    END  dirs_NewerInCurrent .

 DEFINE  purgeIdentical ...
    END  purgeIdentical .

 DEFINE  reportAndPurge ...
	  CALL to  purgeIdentical                  [reportAndPurge]
	  CALL to  purgeIdentical                  [reportAndPurge]
	  CALL to  purgeIdentical                  [reportAndPurge]
	  CALL to  purgeIdentical                  [reportAndPurge]
    END  reportAndPurge .

 DEFINE  diffImg ...
    END  diffImg .

 DEFINE  diffVid ...
    END  diffVid .

 DEFINE  diffBin ...
    END  diffBin .

 DEFINE  closeMatchDiff ...
    END  closeMatchDiff .

 DEFINE  diffFile ...
	  CALL to  diffFile                        [diffFile]
	  CALL to  diffImg                         [diffFile]
	  CALL to  diffVid                         [diffFile]
	  CALL to  diffBin                         [diffFile]
    END  diffFile .

 DEFINE  fils_NewerInReference ...
	  CALL to  diffFile                        [fils_NewerInReference]
	  CALL to  closeMatchDiff                  [fils_NewerInReference]
	  CALL to  closeMatchDiff                  [fils_NewerInReference]
	  CALL to  closeMatchDiff                  [fils_NewerInReference]
	  CALL to  closeMatchDiff                  [fils_NewerInReference]
	  CALL to  reportAndPurge                  [fils_NewerInReference]
	  CALL to  reportAndPurge                  [fils_NewerInReference]
    END  fils_NewerInReference .

 DEFINE  fils_NewerInCurrent ...
	  CALL to  diffFile                        [fils_NewerInCurrent]
	  CALL to  closeMatchDiff                  [fils_NewerInCurrent]
	  CALL to  closeMatchDiff                  [fils_NewerInCurrent]
	  CALL to  closeMatchDiff                  [fils_NewerInCurrent]
	  CALL to  closeMatchDiff                  [fils_NewerInCurrent]
	  CALL to  reportAndPurge                  [fils_NewerInCurrent]
	  CALL to  reportAndPurge                  [fils_NewerInCurrent]
    END  fils_NewerInCurrent .

 DEFINE  evaluateDirs ...
	  CALL to  dirs_NewerInReference           [evaluateDirs]
	  CALL to  evaluateFils                    [evaluateDirs]
	  CALL to  dirs_NewerInCurrent             [evaluateDirs]
    END  evaluateDirs .

 DEFINE  evaluateFils ...
	  CALL to  fils_NewerInReference           [evaluateFils]
	  CALL to  fils_NewerInCurrent             [evaluateFils]
	  CALL to  diffFile                        [evaluateFils]
	  CALL to  closeMatchDiff                  [evaluateFils]
	  CALL to  closeMatchDiff                  [evaluateFils]
	  CALL to  reportAndPurge                  [evaluateFils]
	  CALL to  fils_NewerInReference           [evaluateFils]
	  CALL to  fils_NewerInCurrent             [evaluateFils]
    END  evaluateFils .

 DEFINE  scanLibsLoop ...
	  CALL to  evaluateDirs                    [scanLibsLoop]
	  CALL to  evaluateFils                    [scanLibsLoop]
    END  scanLibsLoop .

 [MAIN]   CALL to  promptForReferencePath
 [MAIN]   CALL to  scanLibsLoop
 [MAIN]   CALL to  selectOneOf
 [MAIN]   CALL to  scanLibsLoop
 [MAIN]   CALL to  selectYesNo

Script:

#!/bin/bash

#23456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+123456789+
####################################################################################################
###
###	Script for analyzing bash scripts, identify functions defined, and report where functions called.
###
###	MOTIVATION:  Analysis and documentation of the script COMPARE+PURGE.sh
###
####################################################################################################

doVerb=0

while [ $# -gt 0 ]
do
	case "$1" in
		"--details" ) doVerb=1 ; shift ;;
		"--file" ) input="${2}" ; shift ; shift ;;
		* ) printf "\n\t ERROR:  Bad option used on command line.  Only valid options:  [ --details ] --file {filename} \n Bye!\n\n" ; exit 1 ;;
	esac
done

test -n "${input}" || { printf "\n\t ERROR:  Must provide filename as input parameter!\n Bye!\n\n" ; exit 1 ; }

test -s "${input}" || { printf "\n\t ERROR:  Inapropriate attempt to analyze empty input file!\n Bye!\n\n" ; exit 1 ; }


awk -v dbg="${doVerb}" -v fil="${input}" 'BEGIN{
	gotFunc=0 ;
	split("", funcName ) ;
	funcIndx=0 ;

	abandon=0 ;
	do{
		if( ( getline aLine <fil ) > 0 ){
			pos=index( aLine, "()" ) ;
			if( pos > 0 ){
				#print aLine | "cat 1>&2" ;
				if( aLine !~ "#"funcName[funcIndx] ){
					gotFunc=1 ;
					funcIndx++ ;
					funcName[funcIndx]=substr( aLine, 1, pos-1 ) ;
					if( dbg == 1 ){ printf(" Function  %-30s  ->  funcName[%d]\n", funcName[funcIndx], funcIndx ) | "cat 1>&2" ; } ;
				} ;
			} ;

			#abandon=0 ;
		}else{
			abandon=1 ;
		} ;
	}while( abandon == 0 ) ;
	if( dbg == 1 ){ print "" ; } ;

	gotFunc=0 ;
}{
	for( i=1 ; i<= funcIndx ; i++ ){
		posN=index( $0, funcName[i] ) ;
		posF=index( $0, "()" ) ;
		if( posN > 0 && posF == 0 ){
			if( gotFunc == 1 ){
				#printf("\t\t [%s]  CALL to %s\n", funcThis, funcName[i] ) ;
				if( dbg == 1 ){
					printf("\t  CALL to  %-30s  [%s]\n", funcName[i], funcThis ) ;
				}else{
					printf(" CALL to  %-30s  [%s]\n", funcName[i], funcThis ) ;
				} ;
			}else{
				if( dbg == 1 ){
					printf(" [MAIN]   CALL to  %s\n", funcName[i] ) ;
				}else{
					printf(" CALL to  %-30s  [MAIN]\n", funcName[i] ) ;
				} ;
			} ;
		} ;
	} ;

	pos=index( $0, "()" ) ;
	if( pos > 0 ){
		if( $2 ~ /^#/ ){
			gotFunc=0 ;
			pos=index( $0, "#" ) ;
			rem=substr( $0, pos+1 ) ;
			gsub( /[(][)]/, "", rem ) ;
			if( dbg == 1 ){ printf("    END  %s .\n\n", rem ) | "cat 1>&2" ; } ;
		}else{
			gotFunc=1 ;
			funcThis=substr( $0, 1, pos-1 ) ;
			if( dbg == 1 ){ printf(" DEFINE  %s ...\n", funcThis ) | "cat 1>&2" ; } ;
		} ;
	} ;
#}END{
}' <"${input}"

Enjoy! :slight_smile:

1 Like