On 28 Oct 1998, in message <[EMAIL PROTECTED]>
  Tony Nugent <[EMAIL PROTECTED]> wrote:
| [I love talking to myself:-]

Oh please! Let me talk to you too!

| > On Sat Oct 24 1998 20:06, Coran Fisher aka The Doctor wrote:
| > There's more than one way to do this.  An example might be useful:
| > % find /usr/include -follow -name \*.h | xargs grep time /dev/null
| 
| I just had cause to do something similar to this, but it involved editing a
| whole bunch of html files to replace all instances of a URL address with
| another.  While I was at it I also wanted to add a "background" image to
| the <BODY> tag.

I hope you put in a BGCOLOR tag as well. If the image is slow to load or
fails to load, you page will look pretty wonky. I usually pick a BGCOLOR
matching the average colour of the BACKGROUND image. Don't get me started on
forgetting the TEXT and LINK colours as well...

| Pretty boring job to do by hand, one file at a time.
| 
| I thought about using sed, but I'd have to do it from a shell script (or
| bash function) because I'd have to filter each file, save the output
| into a temporary file, then copy this over the top of the original one.
| Tricky and messy.

But very tractable. I append "bsed" (batch sed) a wrapper for sed which does
exactly this. I use it all the time. One of the most useful things I've ever
written.

| But then perl came to the rescue...
| % find . -name \*.html -print | \
|     xargs perl -pi 's/<BODY>/<BODY background=mat3.jpg>/i'
| Magical stuff, eh?  :)

Not as magical as you might hope. Like cvs, "perl -i" makes a _new_ file,
moving the old one aside.

        - this breaks hard links
        - this trashes the file permissions (resets them per your umask)

This simple issue makes me never use the -i option to perl.

Bsed takes care to do it right. Install it and enjoy.
--
Cameron Simpson, DoD#743        [EMAIL PROTECTED]        http://www.zip.com.au/~cs/

#!/bin/sh
#
# bsed - batch edit with sed
#       - Cameron Simpson <[EMAIL PROTECTED]>
#

cmd=`basename "$0"`
usage="Usage: $cmd [-v] [-i suf] {-f script|{-e sedcmd}...|sedcmd}... [--] files...
        -v              Verbose.
        +v              Not verbose.
        -i suf          Copy original to original.suf if changed.
        -f script       Passed to sed.
        -e sedcmd       Passed to sed.
        sedcmd          Passed to sed."

fflag=
diff='diff -u'
sedscript=
ecmd=
[ -t 1 ] && verbose=1 || verbose=
ibak=

set x $BSEDOPTS ${1+"$@"}; shift

badopts=
while :
do
    case $1 in
        --)     shift ; break ;;
        -v)     verbose=1 ;;
        +v)     verbose= ;;
        -f)     fflag=1; sedscript=$2; shift ;;
        -i)     ibak=$2; shift ;;
        -i?*)   ibak=`expr "x$1" : 'x-i\(.*\)'` ;;
        -e)     ecmd="$ecmd
                        $2"; shift ;;
        -*)     echo "$cmd: $1: unknown option" >&2
                badopts=1
                ;;
        *)      break ;;
    esac
    shift
done

sedf=sed
if [ $fflag ]
then
    sedf="$sedf -f \"\$sedscript\""
else
    if [ -z "$ecmd" ]
    then
        case $# in
            0)  echo "$cmd: missing sed command" >&2
                badopts=1
                ;;
            *)  ecmd=$1; shift ;;
        esac
    fi
    sedf="$sedf -e \"\$ecmd\""
fi

[ $# = 0 ] && { echo "$cmd: missing filenames" >&2; badopts=1; }

[ $badopts ] && { echo "$usage" >&2; exit 2; }

tmp=/tmp/$cmd.$$
trap 'rm -f "$tmp"; exit 1' 1 2 15

xit=0
ok=1
while   [ $ok ] || xit=1        # catch exit from previous loop
        [ $# -gt 0 ]            # loop condition
do

    file=$1; shift

    if [ "x$file" = x- ]
    then
        [ $verbose ] && echo "reading filenames from stdin..."
        set x `cat` ${1+"$@"}; shift
        continue
    fi

    ok=

    if [ ! -f "$file" ]
    then
        echo "$cmd: $file: not a regular file, skipped" >&2
        continue
    fi

    bakfile= bakdir=
    case "$ibak" in
        '')     ;;
        */)     case "$file" in
                        */*)    bfile=`basename "$file"`
                                dfile=`dirname "$file"`
                                ;;
                        *)      bfile=$file
                                dfile=.
                esac
                bakdir=$dfile/$ibak
                bakfile=$bakdir/$bfile
                ;;
        *)      bakfile=$file.$ibak
                ;;
    esac

    if [ -n "$bakfile" ] && [ -f "$bakfile" ]
    then
        echo "$cmd: $file: backup $bakfile already exists, original unchanged" >&2
        continue
    fi

    [ $verbose ] && echo "$file ..."

    if eval "$sedf <\"\$file\" >\$tmp"
    then
        # check for changes
        if cmp -s "$file" "$tmp"
        then
            ok=1                # no change
            continue
        else
            if [ ! -s "$tmp" ]
            then
                echo "$cmd: warning: tmpfile empty! skipping $file" >&2
                continue
            fi
        fi
        [ $verbose ] && $diff "$file" "$tmp"

        # ensure we have a backup
        if [ -n "$bakfile" ]
        then
            if [ -f "$bakfile" ]
            then
                echo "$cmd: $file: backup $bakfile already exists, original unchanged" 
>&2
                continue
            fi
            if cp "$file" "$bakfile" && cmp -s "$file" "$bakfile"
            then :
            else echo "$cmd: $file: can't make backup, original unchanged" >&2
                 continue
            fi
        fi

        # copy change version in
        if cat "$tmp" > "$file" && cmp -s "$tmp" "$file"
        then
            ok=1        # backup & update ok
            continue
        fi

        echo "$cmd: $file: can't update" >&2
        if [ -n "$bakfile" ]
        then
            if cat "$bakfile" > "$file"
            then
                echo "$cmd: $file: original restored" >&2
                rm "$bakfile"
            else
                echo "$cmd: $file: restore failed; original left in $bakfile" >&2
            fi
        else
            echo "$cmd: $file: no backup, may be corrupt" >&2
        fi
    else
        echo "$cmd: $file: edit fails; original unchanged" >&2
    fi
done

rm -f "$tmp"

exit $xit

Reply via email to