Subject: Re: sh -c
To: David Laight <david@l8s.co.uk>
From: Greg A. Woods <woods@weird.com>
List: tech-userlevel
Date: 05/01/2003 16:02:18
[ On Thursday, May 1, 2003 at 19:44:49 (+0100), David Laight wrote: ]
> Subject: Re: script command
>
> > A bit far afield but since the common direction seems to be touting
> > POS-ix, one would think that sh knew how to parse options in a similar
> > manner to, or in fact use, getopt(3), and abide by its constructs; i.e.
> >
> > sh -c -x command -y would (try to) execute "-x", while
> > sh -x -c command -y would (try to) execute "command".
> >
> > [note that quotes are needed around "command args..." in order to get
> > it to work properly.]
>
> Indeed our shell does obey posix (since I fixed it a few months ago).
> The synopsis has:
>
> sh -c [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]
> [+o option_name] command_string [command_name [argument ...]]
>
> sh -c "command args" will look for a file command\ args, not execute
> command with args.
Are you sure? The following is from a NetBSD 1.6R installed from a
releng snapshot built on 2003/04/25:
# sh -c 'echo hello there'
hello there
# sh -c 'cat hello there'
cat: hello: No such file or directory
cat: there: No such file or directory
If what you say is what you think POSIX says, then I would say POSIX is
broken w.r.t. the traditional behaviour it should be documenting.
However I think you've mis-interpreted your own implementation! ;-)
IEEE POSIX Std. 1003.1-2001 says w.r.t. the '-c' form:
sh -c [-abCefhimnuvx] [-o option] [+abCefhimnuvx] [+o option] command_string [command_name [argument...]]
The following additional options shall be supported:
-c
Read commands from the command_string operand. Set the
value of special parameter 0 (see Special Parameters) from
the value of the command_name operand and the positional
parameters ($1, $2, and so on) in sequence from the
remaining argument operands. No commands shall be read
from the standard input.
I interpret that to say that "sh -c string" is the same as putting that
string in a file and running it as a script:
# echo 'echo hello there' > test.script
# sh test.script
hello there
Indeed that's how I've always understood 'sh -c', right from V7.
P1003.1-2001 has the added priviso that in the invoked shell the
expansion of $0 will be 'command_name' and $1 will be 'argument', and so
on, but that's a new non-traditional thing as far as I can tell.
The difference being that without the '-c' the command string comes from
the script file specified on the command line, and there is no
"command_name" parameter either as $0 comes from the script name:
$ uname -r
1.5W
$ echo 'echo hello 0=$0 1=$1 2=$2' > test.script
$ sh ./test.script
hello 0=./test.script 1= 2=
$ sh ./test.script foo bar none
hello 0=./test.script 1=foo 2=bar
So, to test for proper 1003.1-2001 conformance of the '-c' form:
$ uname -r
1.5W
$ echo '#! /bin/sh' > test.script
$ echo 'echo hello 0=$0 1=$1 2=$2' >> test.script
$ chmod +x test.script
$ sh -c ./test.script foo bar none
hello 0=test.script 1= 2=
Yup, definitely "broken" as of a year ago.... How about now?
# uname -r
1.6R
# echo '#! /bin/sh' > test.script
# echo 'echo hello 0=$0 1=$1 2=$2' >> test.script
# chmod +x test.script
# sh -c ./test.script foo bar none
hello 0=./test.script 1= 2=
Seems to still be "broken".
So I'm not sure what you think you've fixed.
However both current and past behaviour is compatible with /bin/sh on
SunOS-5.6, as well as ksh:
$ sh -c ./test.script foo bar none
hello 0=./test.script 1= 2=
$ ksh -c ./test.script foo bar none
hello 0=./test.script 1= 2=
$ /usr/xpg4/bin/sh -c ./test.script foo bar none
hello 0=./test.script 1= 2=
So although the NetBSD shell has behaved identically to traditional
implementations both before and after your changes, POSIX defines a new
behaviour (and as yet I can't find a rationale section explaining why).
--
Greg A. Woods
+1 416 218-0098; <g.a.woods@ieee.org>; <woods@robohack.ca>
Planix, Inc. <woods@planix.com>; VE3TCP; Secrets of the Weird <woods@weird.com>