Finding the last arg

Bob McGowen x4312 dept208 bob at wyse.wyse.com
Thu Dec 27 09:44:52 AEST 1990


In article <18476 at shlump.nac.dec.com> lan_csse at netrix.nac.dec.com (CSSE LAN Test Account) writes:
>Well, it should have been easy, but everything I've tried has failed, so
>I'll go to the experts... (;-)
>
>What I've been trying to do is write a script whose semantics are sort of
>like the cp/mv/ln commands, in that the last argument is special.  If it
>is a directory, I want to do something different that amounts to appending
>character strings to its name to give file name[s] within the directory;
>if it is an ordinary file, I just want to use its name.
>
>The problem is that I can't figure out any Bourne-shell expression that
>gives the last argument.  In C-shell, it's easy (argv[$#]).  But I need
>to write Bourne shell scripts.  In fact, they need to be BSD bourne shell
>scripts rather that ATT Bourne shell scripts.  The difference is probably
>significant here, because of the differences in the way these two Bourne

  As an aside, could you explain this comment?  I have had minimal contact
  with BSD, but my experience does not seem to support this statement.

>shells handle variables.  Actually, it'd be really nice to find a solution
>that is portable, but that may be just a dream.
---deleted discussion---
>Any ideas?

Three solutions came to mind:  1) using eval; 2) using shift; 3) using a
combined while loop/if statement with the shift.

   1)  eval echo this is the last argument \$$#

       This works because the shell evaluates the right $ with the # to
       give the last argument (not really, but see later), then re-reads
       the line with the value of this number following the first $, which
       it now sees as an unprotected character and gives the substituted arg
       that matches.  Now for the "not really":  this will only work for
       a list of args that is not bigger than nine.  The tenth arg would
       result in output like:

		this is the last argument a0

       where the a is arg 1 ($10 is the concatenation of $1 and 0).

   2)  shift `expr $# - 1`
       echo the last arg is $1

       The Bourne shell on AT&T's SysV/386 and the Sun OS support a
       numeric argument to the shift.  This number of args are shifted
       out of the list.  So if there are ten args, expr gives nine for
       the shift, the last arg becomes $1.  The problem here is that
       all the preceding args are thrown away.

   3)  while [ ! -z "$1" ]
       do
	  if [ $# -eq 1 ]
	  then
	     last=$1
	     shift
	  else
	     rest="$rest $1"
	     shift
	  fi
       done

       Each argument is collected as encountered on the command line
       (except for the case where it contains white space -- "a b";
       this is a little hard to handle with this type of structure
       because the "arguments" are parsed three times: once as $1,
       again in the if to construct the $rest and later whenever $rest
       is used).  All except the last are collected into the variable
       rest, the last is in the variable last.  You can now manipulate
       the parts as needed.  For instance, to create a path name
       with the last arg as the first component:

       for item in $rest
       do
	  echo $last/$item
       done

I hope this slightly lengthy discussion helps.


Bob McGowan  (standard disclaimer, these are my own ...)
Product Support, Wyse Technology, San Jose, CA
..!uunet!wyse!bob
bob at wyse.com



More information about the Comp.unix.shell mailing list