: ########################################################################## # Title : chtext - change text in multiple files # Author : Heiner Steven # Date : 1993-05-13 # Requires : # Category : Text Utilities # SCCS-Id. : @(#) chtext 1.6 04/07/08 ########################################################################## # Description # - This script basically does the following: # sed 's/old/new/g' < IN > TMP && mv TMP IN # # Caveats # o Should have an option to enable the special meaning of "&" # in the "sed" expression (suggested by Douglas Kramer) ########################################################################## PN=`basename "$0"` # Program name VER='1.6' usage () { echo >&2 "$PN - change text in multiple files, $VER Heiner Steven 1993-2004; Public Domain usage: $PN [-fq] [-s searchpat] [-n newtext] file [...] -s: search expression that should be replaced -n: new text -f: remove (instead replace) search expression -q: quiet mode If the search pattern or the new text is not specified on the commandline, $PN will prompt for it." exit 1 } msg () { [ "$Quiet" = true ] && return 0 echo >&2 "$PN:" "$@" } # GetStr (prompt, varname) # Note: "call by name", varname is the name of a variable, not a value: # Example: file=test.txt; GetStr "file name" file GetStr () { test $# -eq 2 || return 1 answer= echo "$1: \c" # some UNIXes need "echo -n" read answer || { echo; exit 1; } eval $2=\$answer # assign new value to variable return 0 } Tmp="cht$$" # Temporary file OldText= # Search pattern NewText= # New Text Interactive=true # Parameter -f Quiet=false # Parameter -q while [ $# -gt 0 ] do case "$1" in -s) OldText="$2" shift ;; -n) [ $# -gt 1 ] && Interactive=false NewText="$2" shift ;; -f) Interactive=false ;; -q) Quiet=true ;; --) shift; break ;; # Files will follow -*) usage ;; *) break ;; # File name(s) esac shift done [ $# -lt 1 ] && usage if [ -z "$OldText" ] || [ -z "$NewText" ] then if [ "$Quiet" != true ] then echo >&2 "$PN - change text, $VER" echo >&2 msg "Files to change:" "$@" fi if [ -z "$OldText" ] then GetStr "old text" OldText [ -z "$OldText" ] && exit 1 fi if [ -z "$NewText" ] && [ "$Interactive" = true ] then GetStr "new text" NewText if [ -z "$NewText" ] then echo >&2 "$PN: Really remove '$OldText' (y/n)? \c" read answer || exit 1 case "$answer" in y|true) break ;; *) exit 1 ;; esac fi fi fi if [ "$OldText" = "$NewText" ] then echo >&2 "$PN: old and new text are identical - no substitution necessary!" exit 1 fi case "$OldText$NewText" in **) echo >&2 " $PN: ERROR: text to change cannot contain an ^A (ASCII 1) character, because it is used internally as a delimiting character" exit 1 esac msg "change '$OldText' to '$NewText'" # We are using NewText on the right side of an "sed" expression, and # therefore have to protect the special character '&' from being # interpreted as meaning "the matching text": NewText=`sed 's/&/\\\\&/g' <&2 "$PN: ERROR: no permisson to change '$file' - ignored" errors=`expr $errors + 1` continue } msg "$file" cp -p "$file" "$Tmp" || { echo >&2 "$PN: ERROR: could not create temporary file for '$file'" errors=`expr $errors + 1` continue } sed -e 's'"$OldText"''"$NewText"'g' < "$file" > "$Tmp" || { echo >&2 "$PN: ERROR: could not change '$file'" errors=`expr $errors + 1` continue } if cmp "$file" "$Tmp" >/dev/null then msg "INFO: file has not changed: $file" rm -f "$Tmp" >/dev/null 2>&1 continue fi mv "$Tmp" "$file" || { echo >&2 "$PN: ERROR: could not rename '$Tmp' to '$file' - file not changed!" errors=`expr $errors + 1` continue } done if [ $errors -ne 0 ] then exit 1 fi exit 0