Subject: Re: discrepency beteen /bin/echo and builtin echo of /bin/sh
To: None <tech-userlevel@NetBSD.ORG>
From: Greg A. Woods <woods@weird.com>
List: tech-userlevel
Date: 06/13/2002 04:38:01
[ On Wednesday, June 12, 2002 at 23:37:29 (+0100), Ben Harris wrote: ]
> Subject: Re: discrepency beteen /bin/echo and builtin echo of /bin/sh
>
> In article <20020612193955.87F80AC@proven.weird.com> you write:
> >[ On Monday, June 10, 2002 at 12:41:24 (+0100), Ben Harris wrote: ]
> >> Subject: Re: discrepency beteen /bin/echo and builtin echo of /bin/sh
> >>
> >> Erm, I think SUSv2 was intended to be aligned with POSIX, so that any SUSv2
> >> implementation will also be a POSIX implementation.  This is trivially true
> >> of SUSv3 of course.
> >
> >"aligned with" != "same as"
> 
> You were advocating complying with SUS and not complying with POSIX.  My
> point was that this is impossible.  SUS explicitly defers to POSIX, so any
> SUS implementation must be a POSIX implementation.  Of course, SUSv2 only
> defers to the POSIX standards that were current when it was issued, not to
> future ones.

SUS explicitly extends POSIX and is in some cases more limiting (not
allowing some implementation defined extensions explicitly allowed by
POSIX), and in this case of "echo", at least according to the draft copy
of the version of POSIX 1003.2 that I quoted from (which I believe was
eventually published as the one "deferred" to by SUS v2) SUS v2
explicitly both extends and limits the implemention of "echo"

So, yes a SUS v2 "echo" is strictly in conformance with POSIX 1003.2,
however it is not any more practical a version than a minimally
conforming 1003.2 implementation is.

(it almost seems to me you're using some altered meaning of "defer" that
doesn't match the common English usage)

> This means that arguing the relative merits of our favourite standards is
> pretty much moot, unless you particularly think that SUSv2/1003.2-1992 is
> better than SUSv3/1003.1-2001.

Standards are so wonderful because there are so many to choose from!

Indeed the minimally conforming SUS v2 "echo" is far more pragmatic than
the minimally conforming 1003.2 "echo", though the 1003.2 "echo"
definition allows for the SUS v2 implementation, and also allwo for an
even better implementation as I've proposed.

From all I've seen and heard so far 1003.1-2001 is, like many recent
attempts to refine other standards in this industry, not really a
refinement in many areas but a re-invention by an new hoard of
differently biased people, often with little or no regard for legacy
implementations and uses.  In the case of "echo" it seems the
implementation freedoms that make supporting less portable code much
easier have been squashed for no good reason (or at least none I've
heard yet).

If the published POSIX documents were freely available online I might be
convinced to erase some of my misgivings and defer more to it....  :-)

As I've said I personally would not mind allowing a '-n' option, if and
only if it appears as the first parameter of course, as defined by the
1003.2 draft I quoted (I've never encountered any real-world use of it
that would break with such an implementation that was a union of the SUS
v2 and the original 1003.2 definition.)

> With POSIX and SUS, the terms "option", "operand", and "argument" have
> specialised meanings.  An argument is one of the strings passed as part of
> argv to a utility.  Some of these arguments contain options, some of them
> contain option-arguments, at most one of them contains the end-of-options
> delimeter, and the rest are operands.  Note that this means that no argument
> can both contain options and be an operand.  See
> <http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap12.html> for
> more details.

Well, OK, I'll use those words so as not to confuse those of you so
embedded in the process that those words are all you can keep
straight....  :-)

(I really have grown to dislike the improper use of the word "argument"
to describe a command-line (or function) parameter, but for the sake of
standards conformity....  I've been trying to clean up my own misuse of
this word too, thus my tendency to avoid the POSIX usage)

> Now, the specification for "echo" explicitly states that it shall not
> recognise "--" as the end-of-options delimiter, but as an operand.
> Thus, in the command-line "echo -- foo", there are two operands, "--" and
> "foo".

indeed and of course the result of such a command will be the output of
the seven characters '-', '-', ' ', 'f', 'o', 'o', and '\n'.

> The interesting question is how we analyse the command-lines "echo -n foo"
> and "echo -e foo".  Specifically, are "-n" and "-e" options or operands? 
> How about in "echo -e -n foo" and "echo -n -e foo"?

Why do you ask such silly questions?  The wording I quoted from the
1003.2 draft makes the interpretation of your examples crystal clear for
a minimally conforming implementation:

	$ echo -e foo
	-e foo
	$ 

	$ echo -n foo
	-n foo
	$ 

	$ echo -e -n foo
	-e -n foo
	$ 

	$ echo -n -e foo
	-n -e foo
	$ 

A minimally conforming 1003.2 implementation would also not implement
any backslash escape sequences either, just as it does not implement any
command-line options.

To further demonstrate I'll use the 1003.2-conforming implementation I
proposed earlier, which essentially follows a union of the SUS v.2 and
POSIX 1003.2 specifications.  My proposed implementation defines the
meaning of an initial '-n' or '-e' to match the "traditional" BSD
behaviour:

	$ echo -n foo
	foo$ 

	$ echo -e foo
	foo
	$ 

	$ echo -e -n foo
	-n foo
	$ 

	$ echo -n -e foo
	-e foo$ 
	
Of course my proposed implementation would also always implement the
backslash escape sequences defined in SUS v2, regardless of whether or
not '-e' was given.  The implementation I propose would be the least
detrimental to, and most compatible with, all existing patterns of use
of "echo" I've ever encountered in the past two decades.

A strict SUS v2 implementation would perform your examples like this:

	$ echo -e foo
	-e foo
	$ 

	$ echo -n foo
	-n foo
	$ 

	$ echo -e -n foo
	-e -n foo
	$ 

	$ echo -n -e foo
	-n -e foo
	$ 

(i.e. just as the minimal 1003.2 implementation, since your examples do
not include any use of backslash escape sequences that would
differentiate this example)


Of course to really be 100% portable code using "echo" must still
account for implementations that do not work like the one I propose.
I've found the following to be useful in such portable code:


HAVEPRINT=false ; export HAVEPRINT
if expr "`type print`" : 'print is a shell builtin$' >/dev/null 2>&1 ; then
	HAVEPRINT=true
fi

HAVEPRINTF=false ; export HAVEPRINTF
if expr "`type printf`" : 'printf is a shell builtin$' >/dev/null 2>&1 ; then
	HAVEPRINTF=true
elif expr "`type printf`" : '.* is .*/printf$' >/dev/null 2>&1 ; then
	HAVEPRINTF=true
fi

# always use ``$echo'' if any of the other variables are used...
#
#       $nl - print a newline (always required at end of line if desired)
#       $n - option to turn off final newline
#       $c - escape sequence to turn off final newline
#
# usage for a prompt is:
#
#       $echo $n "prompt: $c"
#
# (note the explicit lack of quoting on $n)
#
# and for a normal line:
#
#       $echo "message$nl"
#
if $HAVEPRINT ; then
	echo=print
	nl='\n'
	n='-n'
	# XXX in theory '\c' is equivalent of '-n' in most shells
	c=''
elif $HAVEPRINTF ; then
	echo=printf
	nl='\n'
	n=''
	c=''
else
	echo=echo
	(echo "hi there\c" ; echo " ") >$HOME/echotmp
	if grep c $HOME/echotmp >/dev/null 2>&1 ; then
		nl=''
		n='-n'
		c=''
	else
		nl=''
		n=''
		c='\c'
	fi
	rm -f $HOME/echotmp
fi


-- 
								Greg A. Woods

+1 416 218-0098;  <gwoods@acm.org>;  <g.a.woods@ieee.org>;  <woods@robohack.ca>
Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>