#!/bin/ksh

# Version 1.1 Added -n option to select which instance of target is changed, 10/23/01 jsmith

# Version 1.2 Added -k option to specify a keyword from which to start changes, 10/24/01 jsmith

 

function PrintUsage

{

  echo ""

  echo "USAGE:        changeSTRING [options] <target_string> <new_string> [file_name [filename2 ...]]"

  echo "           changeSTRING [options] <target_string> <new_string> [directory_name] "

  echo "           changeSTRING [options] <target_string> <new_string> "

  echo

  echo "Replaces all instances of target_string with new_string in the "

  echo "specified file(s)."

  echo

  echo "You can enter 1 or multiple specific file names, with or without a "

  echo "qualified path.  If no path is given, the current directory is "

  echo "assumed.  File names should be separated by blanks."

  echo

  echo "If you specify a directory name, then ALL files, containing "

  echo "target_string, in that directory will me changed."

  echo

  echo "If you don't specify either a file_name OR a directory name then ALL "

  echo "files in the CURRENT directory will be searched."

  echo

  echo "OPTIONS: All options MUST be specified before any other parameters."

  echo

  echo "  \"-f\" will cause all specified files to be change regardless of their"

  echo "  write protection.  Files will be left as write ENABLED.  \"-f\" MUST be the "

  echo "  FIRST parameter."

  echo

  echo "  \"-n number\" will cause only the number'th instance of the target string to be changed on"

  echo "  each line in the specified file where Targe appears."

  echo "  If there are two instances of target on a line, changeSTRING will, by default, change both."

  echo "  Ifyou were to include \"-n 2\" on the command line, only the 2nd instance would be changed."

  echo

  echo "  NOTE: if there are not \"number\" occurences of target on a line, then NO"

  echo "  changes will be made on that line.  It is \"number\" or nothing."

  echo

  echo "  NOTE: The \"-n\" option modifes the default behavour for a single line in the specified file."

  echo "  changeSTRING will still change Target for every line in the file.  If you want to modify"

  echo "  which lines in the file changeSTRING operates on, you have to use the \"-k\" option."

  echo

  echo "  The first instance \"-k Keyword\" will cause changeSTRING to search the file for Keyword "

  echo "  and then start making string substuitions.  Instances of target BEFORE Keyword will not be "

  echo "  changed.  If Keyword contains blanks, it must be placed in double quotes (\")."

  echo   

  echo "  \"-k Keyword\" can be entered as an option a 2nd time with a different (or the same) "

  echo "  Keyword value.  This will cause changeSTRING to isolate the text between the two Keywords"

  echo "  and make the changes there.  Instances of Target before KeyWord1 and after KeyWord2 would"

  echo "  not be changed."

  echo

  echo "  \"-1\" can be used to limit the change to a single line, instead of the whole file.  Only the first"

  echo "  line where Target occurs will be changed."

  echo

  echo "NOTE: changeSTRING does not change files in sub-directories.  These "

  echo "      must be changed with another changeSTRING command."

  echo

  echo "NOTE: !!!! changeSTRING does NOT MAKE BACKUPS !!!!"

  echo

  echo "NOTE: ALL the options may be used together."

  echo

  exit 1

}

 

if [[ $2 = "" || $1 = "-h" ]]; then PrintUsage; fi

 

Force="-p"

changeparm="g"

KeyWord1=""

KeyWord2=""

changecount=0

 

while (( 1 == 1)); do

  case $1 in

    -f)  Force="-fp"

         shift

         ;;

    -n)  changeparm="$2"

         shift

         shift

         ;;

    -k)  if [[ $KeyWord1 = "" ]]; then KeyWord1="$2"; else KeyWord2="$2"; fi

         shift

         shift

         ;;

    -1)  changecount=1

         shift

         ;;

     *)  break

         ;;

  esac

done

 

oldstr="$1"; shift

newstr="$1"; shift

 

if [[ $1 = "" ]]; then

  file_list=`ls -d ./*`

elif [ -d $1 ]; then

  file_list=`ls -d $1/*`

else

  file_list="$@"

fi

 

if [[ "$oldstr" = "$newstr" ]]; then

  echo "STRINGS ARE THE SAME -- no change possible -- Exiting"

  exit 0

fi

 

let file_count=0

Error=0

for file in `grep -l "$oldstr" $file_list`; do

  Error=0

 

  if [ ! -a $file ]; then

    echo "$file does not exist!"

 

  elif (( `grep -c "$oldstr" $file` == 0 )); then

    echo "Target String Not Found in $file"

 

  else

    cp -f $file $file.SaVe

 

    if [[ $KeyWord1 != "" && `grep "$KeyWord1" $file` != "" ]]; then

      let j1=`grep -n "$KeyWord1" $file | head -1 | cut -d":" -f1`

      let j2=$j1+1

 

      head -$j1 $file > $file.tmp

      tail +$j2 $file > $file.tmp.2

      mv -f $file.tmp.2 $file

 

    elif [[ $KeyWord1 != "" ]]; then

      echo "!!! $KeyWord1 not found !!!"

      Error=1

    fi

 

    if [[ $KeyWord2 != "" && `grep "$KeyWord2" $file` != "" ]]; then

      let j2=`grep -n "$KeyWord2" $file | head -1 | cut -d":" -f1`

      let j1=$j2-1

 

      head -$j1 $file > $file.tmp.2

      tail +$j2 $file > $file.tmp.trailer

      mv -f $file.tmp.2 $file

 

    elif [[ $KeyWord2 != "" ]]; then

      echo "!!! $KeyWord2 not found !!!"

      Error=2

    fi

 

    if [[ $changecount != "0" ]]; then

      let j1=`grep -n "$oldstr" $file | head -1 | cut -d":" -f1`

      let j2=$j1+1

 

      tail +$j2 $file > $file.tmp.trailer.2

      cat $file.tmp.trailer >> $file.tmp.trailer.2 2>/dev/null

      mv -f $file.tmp.trailer.2 $file.tmp.trailer

 

      head -$j1 $file | tail -1 > $file.tmp.2

 

      let j1=$j1-1

      head -$j1 $file >> $file.tmp

 

      mv -f $file.tmp.2 $file

 

    fi

 

    if [[ $Error = "0" ]]; then

      cat $file | sed -e "s+$oldstr+$newstr+$changeparm" >> $file.tmp;

      if [[ $? != "0" ]]; then

        echo "!!! cat/sed command did not work !!!"

        Error=3

      else

        cp $Force $file.tmp $file

        if [[ $? != "0" ]]; then

          echo "!!! cp command did not work !!!"

          Error=4

        else

          if [[ -s $file.tmp.trailer ]]; then

            cat $file.tmp.trailer >> $file

            rm $file.tmp.trailer

          fi

        fi

      fi

    fi

 

    if [[ $Error = "0" ]]; then

     echo $file changed

     let file_count=file_count+1

     rm -f $file.SaVe

    else

     echo "Error Encountered ... $file NOT changed !!!"

     chmod +w $file.SaVe

     mv -f $file.SaVe $file

    fi

 

    rm $file.tmp* 2>/dev/null

  fi

done

 

if (( file_count == 0 && Error == 0 )); then

  echo "Target string NOT found in file list"

elif (( file_count == 0 )); then

  echo "NO files changed\n"

elif (( file_count == 1 )); then

  echo "1 file changed\n"

else

  echo "$file_count files changed\n"

fi

 

exit $Error