Subject: Re: New xargs, was Re: upgrade to mv
To: NetBSD Userlevel Technical Discussion List <tech-userlevel@NetBSD.ORG>
From: Greg A. Woods <woods@weird.com>
List: tech-userlevel
Date: 08/16/2001 11:39:03
[ On Thursday, August 16, 2001 at 10:28:57 (-0500), Frederick Bruckman wrote: ]
> Subject: Re: New xargs, was Re: upgrade to mv
>
> As a matter of fact, the argument numbering has to start with "$0" for
> some reason that's a complete mystery to me...
> 
> fredb@tautology-> echo foo bar | xargs -n2 sh -x -c 'echo $0 BLAH $1 BLAH'
> + echo foo BLAH bar BLAH
> foo BLAH bar BLAH
 
That's because of the somewhat bizzare way parameters are set from the
command-line for "sh -c" scripts.  The first parameter is always used to
set $0, and the remainder are used for the rest of the positional
parameters.

This might help visualize what's going on a bit better:

	$ echo foo bar | xargs -p sh -x -c 'echo 0:$0 1:$1'
	sh -x -c echo 0:$0 1:$1 foo bar?...y
	+ echo 0:foo 1:bar
	0:foo 1:bar

I'm not sure why this isn't documented in our sh(1), but it is more or
less partly documented in our ksh(1) synopsis:

   ksh [+-abCefhikmnprsuvxX] [+-o option] [ [ -c command-string [command-name] | -s | file ] [argument ...] ]

but not very well in the body of the manual:

       0      The   name   the  shell  was  invoked  with  (i.e.,
              argv[0]), or the command-name  if  it  was  invoked
              with  the  -c  option and the command-name was sup-
              plied, or the file argument, if  it  was  supplied.
              If  the  posix option is not set, $0 is the name of
              the current function or script.


       -c command-string
              the shell executes the command(s) contained in com-
              mand-string

Historically I don't remember what happened, though I suspect it's
"always been this way".

However all but one of the versions of the "real" Bourne Shell manuals I
can find are silent on what happens to additional parameters after the
'-c command-string'.  That one which isn't silent is the Research UNIX
10'th Edition manual, which explicitly says they are ignored.

Both the early Korn Shell manuals (at least up to ksh88e or so) and the
book are similarly silent though one could construe the synopsis to say
that they are positional args (with the discovery that the first is $0
to be left as an exercise for the reader! ;-):

       ksh [ +-aefhikmnprstuvx ] [ +-o option ] ... [ -c string ] [ arg . . . ]

By ksh88i though (the version included in Solaris-2.7), the manual
finally includes a full and proper explanation of what's going on:

    -c         Read commands from  the  command_string  operand.
               Set  the  value  of  special  parameter 0 from the
               value of the command_name operand  and  the  posi-
               tional  parameters ($1, $2, and so on) in sequence
               from the remaining arg operands. No commands  will
               be read from the standard input.


So, in other words what you really want is:

	$ echo foo bar | xargs -p sh -x -c 'echo 0:$0 1:$1 2:$2' scriptname
	sh -x -c echo 0:$0 1:$1 2:$2 scriptname foo bar?...y
	+ echo 0:scriptname 1:foo 2:bar
	0:scriptname 1:foo 2:bar

I note though that on Solaris 2.7 all the shells work the same:

$ echo foo bar | xargs /usr/5bin/sh -c 'echo 0:$0 1:$1 2:$2' scriptname
0:scriptname 1:foo 2:bar
$ echo foo bar | xargs /bin/sh -c 'echo 0:$0 1:$1 2:$2' scriptname   
0:scriptname 1:foo 2:bar
$ echo foo bar | xargs /sbin/sh -c 'echo 0:$0 1:$1 2:$2' scriptname 
0:scriptname 1:foo 2:bar
$ echo foo bar | xargs /bin/ksh -c 'echo 0:$0 1:$1 2:$2' scriptname
0:scriptname 1:foo 2:bar
$ Version M-11/16/88i               

-- 
							Greg A. Woods

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