Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 Mar 2003 18:38:23 +0200
From:      Giorgos Keramidas <keramida@ceid.upatras.gr>
To:        Kok Kok <cckok002000@yahoo.ca>
Cc:        freebsd-questions@FreeBSD.ORG
Subject:   Re: sed to replace the words
Message-ID:  <20030312163823.GC5097@gothmog.gr>
In-Reply-To: <20030312061655.26510.qmail@web13305.mail.yahoo.com>
References:  <20030312061655.26510.qmail@web13305.mail.yahoo.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2003-03-12 01:16, Kok Kok <cckok002000@yahoo.ca> wrote:
> Hi all
>
> I have question how to replace words using sed
>
> ./script 61.100 192.168
>
> The script is
>
> #!/bin/sh
> sed -e 's/$2/$1/g' file > newfile
>
> The problem is 192.168 can't replace 61.100 in the
> newfile

. The sed utility won't see the value of $1 or $2 in this script,
  since you used simple quotes, which inhibit shell variable
  substitution.

. The order of $1 and $2 is reversed.

. Even if you swap $1 and $2 and change ' to ", the results can be
  weird for patterns that include the '.' character since it's a
  special sed character that matches *any* character.  You need to
  escape it with a backslash (\) before testing it on real files.

. The name of 'newfile' is hardwired, which means you can't run the
  script to substitute "$1" to "$2" on many files.

One example of doing this with a relatively easy way would be:

   1 #!/bin/sh
   2
   3 if [ $# -lt 2 ]; then
   4         echo "usage: `basename $0` p-before p-after [file ...]" >&2
   5         exit 1
   6 fi
   7
   8 p_before="$1"
   9 p_after="$2"
  10
  11 shift && shift
  12 for fname in "$@" ;do
  13     echo "Filtering ${fname} ..."
  14
  15     # Escape '.' and '|' in $p_before to avoid matching too many
  16     # things.
  17     p_before=$(echo "${p_before}" | sed -e 's|\.|\\.|g' -e 's,|,\\|,g')
  18
  19     # Filter, using a temp file.
  20     tmpfile=$(mktemp ${TMPDIR:-/tmp}/sedXXXX 2>&1 || echo "")
  21     if [ X"${tmpfile}" = X"" ]; then
  22         echo "Can't create temp file." >&2
  23         exit 1
  24     fi
  25     sed -e "s|${p_before}|${p_after}|g" "${fname}" > "${tmpfile}"
  26     cat "${tmpfile}" > "${fname}"
  27     /bin/rm -f "${tmpfile}"
  28 done

This script when run on a sample test I did seems to do what you
asked, avoiding unnecessary matches:

  giorgos@gothmog[18:26]/home/giorgos$ cat koko
  This is a test line that should remain intact, despite having 150\.140 in it.
  The lines that include 150.140 should match and be changed.
  All other lines stay the same, since i.e. 150 140 doesn't match.

  giorgos@gothmog[18:26]/home/giorgos$ sh lala.sh 150.140 192.168 koko
  Filtering koko ...

  giorgos@gothmog[18:26]/home/giorgos$ cat koko
  This is a test line that should remain intact, despite having 150\.140 in it.
  The lines that include 192.168 should match and be changed.
  All other lines stay the same, since i.e. 150 140 doesn't match.

There are quite a few tricks in that script which you probably don't
need, but it does what you asked.  Some sort of error checking for sed
failures should be added, and you should probably check that it makes
sense to overwrite the original file after sed is done, but well...
that's another thing.

- Giorgos


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030312163823.GC5097>