From: john@physiol.su.OZ.AU (John Mackin)
Subject: Re: What's wrong with this sed command?
Summary: A lot
Organization: Department of Physiology, University of Sydney, Australia
Date: Thu, 23 Jul 1992 09:00:23 GMT

Below, > is someone called `Glaze' who seemed to go to some trouble to
conceal their identity (either that, or their software is more broken
than I can easily believe), and >> is Glaze quoting the original poster,
whose identity Glaze chose to suppress -- and unfortunately my news
machine doesn't have the original article.

>> I'm trying to use sed to trim off all leading "./" patterns from source
>> filenames in make rules. On an IBM RS6000 the following works as I expected:
>>
>>    echo 'enquire.o: ./././enquire.c' | sed 's?: \(\./\)\{1,\}?: ?'
>> yielding
>>    enquire.o: enquire.c
>>
>> On our other systems (Sun-4, HP, SGI, and Motorola 68040) it prints
>> different results. The HP doesn't trim any "./" patterns, while the Sun,
>> Moto, and SGI all trim one pattern.
>>
>> Have I incorrectly specified the sed command or are one (or more) of the
>> vendors' sed implementations incorrect? If so, which one(s)? I'm inclined to
>> believe the IBM is correct and the others are bugged.
>
> I'm inclined to believe the IBM is incorrect and most of the others are
> correct. Your sed should be trying to match ONE pattern of the form
> ": ./"[blah]  and it does(on most machines) and replaces it. What you
> want is for it to match multiple "./"s after the ": ", so try
>    echo 'enquire.o: ./././enquire.c' | sed 's?: [\./]*?: ?'

Glaze's inclination is into error.  The real question the original
poster has to ask himself (yes, I know it's a sexist usage, but I
couldn't bring myself to write "themself") here is: do I want this
sed script to be -portable-??  If you do, then you cannot do this in this
way with sed (as I explain below).  If you only care about what it
does on one particular machine, and you just want to know what
behaviour is `correct', then you have to define your standard of
correctness.

Now, some people might call me reactionary, but to me, the standard
of correctness for Unix commands is the Seventh Edition manuals.
These were published by HRW, and were once widely available; I don't 
know if they are still in print.  I've looked in my copy, and neither
the sed manual entry nor the sed paper in Volume 2 says one word about
any \{m,n\} stuff.  Therefore, if I were writing a sed script that I
wanted to be portable, I would not use such stuff.  For my money,
the only one of the original poster's machines that is doing the
right thing is the HP: it is all the others that have sed bugs here.
(My Ultrix 4.2 DECstation (unsurprisingly -- DEC don't break the commands,
in general) does the same thing, stripping nothing.)

As for Glaze's proposed solution, I am afraid it is bogus.  Yes, it
will `work', in that it will strip as many ./'s as are there,
but it will also strip, for example, "...///" -- it will strip
_any combination of dot and slash (and backslash, see below)
characters in the target position_, which is hardly what the
original poster wanted.

The other error in Glaze's proposal involves the backslash inside
the square brackets.  In a character class, there are no metacharacters,
and writing a backslash introduces a backslash into the class.
So the `correct' way to write Glaze's command would be:

	sed 's?: [./]*?: ?'

What the original poster wants cannot be done in one step with the ed
subset of regular expressions (as used by sed).  If sed accepted full regular
expressions, a la egrep, then the command would be:

	sed 's?: (\./)*?: ?'		WRONG WRONG WRONG

but since sed doesn't do full RE's, that won't work.  You need
another approach.  Since you can't do it in one step, do it
in several:

	sed -e ': loop' -e 's?: ./?: ?' -e 't loop'

Easy, and I will bet it will work in the great majority of vendor-busted
sed's out there.

Moral: know your tools.

-- 
John Mackin <john@physiol.su.oz.au>
`Even the white bits are black.'