[comp.unix.questions] KSH script arguments

jonc@uts.amdahl.com (Jonathan Chang) (08/30/90)

This is my first visit in this group; hope this is where
all the gurus hang out.  I want to pose a somewhat
trivial question:

How can I extract the last argument to a ksh script?

Example:

	myscript arg1 arg2 arg3

Within the script, I want to (easily) know the value of 'arg3'.  
$# returns the number of arguments, $1 is the first argument, 
but what's the variable that cotains the last argument?

Or can someone explain how to get to it (without shifting)?

P.S. Just to add to the challenge, the number of arguments is variable.

Thanks!

jonc@uts.amdahl.com

gt0178a@prism.gatech.EDU (BURNS,JIM) (08/30/90)

in article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com>, jonc@uts.amdahl.com (Jonathan Chang) says:
> How can I extract the last argument to a ksh script?

I'll answer your question 2 different ways. The more generic approach
would be to set each element of $* to a ksh array variable:

set a b c                              #set "command line parameters"
j=0                                    #index variable
for i                                  #no parameters means use $*
do
arr[$j]=$i                             #set each array element
j=`expr $j + 1`                        #incr. index - spaces ARE significant
done
j=0
for i                                  #echo values in a diff. loop
do
echo 'arg #'$j' is '${arr[$j]}
j=`expr $j + 1`
done
echo ${arr[`expr $# - 1`]}             #last 2 stmts are equiv. for pos. parms.
j=`expr ${#arr[*]} - 1`;echo ${arr[$j]}# but this one is more array generic

its output is:

arg #0 is a
arg #1 is b
arg #2 is c
c
c

The second sol'n is a function I use to replace 'cp' to check that the
last argument to 'cp' resulting from a wildcard expansion is a directory
if the # of parms > 2. Old habits from MSDOS die hard, and I'm always
doing 'cp *pat' thinking that the 'destination' will default to my current
directory. It offers no protection from overwriting the last file on the
expanded command tail if the # of parms = 2. I just loop to find the last
parm.

cp () {
if [ $# -eq 0 ]
   then /bin/cp                        #let /bin/cp print error msg
else
   for i in $@                         #find last parm
   do
      continue
   done
   if [ $# -le 2 -o -d $i ]            #ok if # parms = 2, or last parm is
      then /bin/cp $@                  #directory. /bin/cp prints error msg
   else                                #if # parms = 1
      echo $i: not a directory
   fi
   unset i
fi
}

Note that ksh will complain about $* not being set if you provide no parms
and the ksh flag 'nounset' is on. Use 'set -o' to check your flags, and
'set +o nounset' to turn it off.

Just for fun, here's the same function in csh. It's a little less clean
since I can't get 'if..then..else' to work inside a alias. The 'set j=
garbage string' if the # of parms = 0 just sets a bogus directory name so
that the remaining if's don't croak on an unset $j. Note the body of the
alias is one line.

alias cp \
'set i=(\!*);set j=$i[$#i];if ( $#i == 0 ) /bin/cp;if ( $#i == 0 ) set j=CB6EHVC;if ( $#i == 1 || $#i == 2 || -d $j ) /bin/cp \!*;if ( $#i >= 3  && \! -d $j && $j \!= CB6EHVC ) echo ${j}: not a directory;unset i;unset j'
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

wnp@iiasa.AT (wolf paul) (08/30/90)

In article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com> jonc@amdahl.uts.amdahl.com (Jonathan Chang) writes:
)How can I extract the last argument to a ksh script?
)
)P.S. Just to add to the challenge, the number of arguments is variable.

This works; whether it is the most elegant solution I don't know:

	LASTARG=$(eval "echo \$$#")

Anyone know of a better way?

-- 
Wolf N. Paul, IIASA, A - 2361 Laxenburg, Austria, Europe
PHONE: +43-2236-71521-465     FAX: +43-2236-71313      UUCP: uunet!iiasa.at!wnp
INTERNET: wnp%iiasa.at@uunet.uu.net      BITNET: tuvie!iiasa!wnp@awiuni01.BITNET
       * * * * Kurt Waldheim for President (of Mars, of course!) * * * *

kenney@hsi.UUCP (Brian Kenney) (08/30/90)

In article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com> jonc@amdahl.uts.amdahl.com (Jonathan Chang) writes:
 
>How can I extract the last argument to a ksh script?
>Example:
>	myscript arg1 arg2 arg3
 
>Within the script, I want to (easily) know the value of 'arg3'.  
>$# returns the number of arguments, $1 is the first argument, 
>but what's the variable that cotains the last argument?
 
>Thanks!
>jonc@uts.amdahl.com

args=$*
arg3=${args##* }

You're welcome.

I got this from The Kornshell Command and Programming Language by
Bolsky and Korn.  I highly recommend it.

-- 
       Brian Kenney                                      kenney@hsi.com 

spicer@tci.UUCP (Steve Spicer) (08/30/90)

In article <13160@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS,JIM) writes:
>in article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com>, jonc@uts.amdahl.com (Jonathan Chang) says:
>> How can I extract the last argument to a ksh script?
>

Why not do it the way Korn does it?

eval lastarg='$'$#

It's in the book.

Steven Spicer
Technology Concepts, Inc.
Sudbury MA 01776
spicer@tci.bell-atl.com

brad@SSD.CSD.HARRIS.COM (Brad Appleton) (08/30/90)

In article <858@iiasa.UUCP> wnp@iiasa.UUCP (wolf paul) writes:
>In article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com> jonc@amdahl.uts.amdahl.com (Jonathan Chang) writes:
>)How can I extract the last argument to a ksh script?
>)
>)P.S. Just to add to the challenge, the number of arguments is variable.
>
>This works; whether it is the most elegant solution I don't know:
>
>	LASTARG=$(eval "echo \$$#")
>
>Anyone know of a better way?
>

Actually - this might NOT work properly if the last argument contains a newline
(it will be clobbered) or backslashes that get interpreted by echo (or print).
In any case, you should probably use \${$#} instead of \$$#. A "safer" but
not necessarily better way is to use an array (assuming your version of ksh
does not clobber $* when set -A is used):

set -A argv "$@"    ## dump positional parameters into an array

	## index the last element in the array
    ## this is supremely ugly - even more so since
    ## ${#argv[@]} returns the number of array elements
    ## but the array is 0-based
typeset lastarg=${argv[${#argv[@]}-1]}


from here on in you can use ${argv[i]} instead of $i and 
${argv[*]} (${argv[@]}) in place of $* ($@).

Im still hoping for a better way though! One of the few things I 
like that csh has over ksh, is being able to returns subsets of
an array (a la $argv[5-8], $argv[-3], $argv[4-]) but I still dont
think csh had an "easy" way of getting just the last argument.

______________________ "And miles to go before I sleep." ______________________
 Brad Appleton        brad@travis.ssd.csd.harris.com   Harris Computer Systems
                          ...!uunet!hcx1!brad          Fort Lauderdale, FL USA
~~~~~~~~~~~~~~~~~~~~ Disclaimer: I said it, not my company! ~~~~~~~~~~~~~~~~~~~

jrw@mtune.ATT.COM (Jim Webb) (08/31/90)

In article <13160@hydra.gatech.EDU>, gt0178a@prism.gatech.EDU (BURNS,JIM) writes:
> in article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com>, jonc@uts.amdahl.com (Jonathan Chang) says:
> > How can I extract the last argument to a ksh script?
> 
> I'll answer your question 2 different ways.

....and then takes 60 lines to do it.  A bit long winded :-)

And in article <858@iiasa.UUCP>, wnp@iiasa.AT (wolf paul) writes:

> This works; whether it is the most elegant solution I don't know:
> 
> 	LASTARG=$(eval "echo \$$#")
> 
> Anyone know of a better way?

Almost.  You have to be careful if you have more than 9 arguments....

	$ set a b c d e f g h i j k l m n o p q r s t u v w x y z
	$ eval "echo \$$#"
	b6

b6?  yup....  it turns into echo $26, which is parsed as ${2}6.  To
get around this, one needs some more {}'s:

	$ eval echo \$\{$#\}
	z

Still, very ugly :-)  Any other takers on this one?

Later,

-- 
Jim Webb                "Out of Phase -- Get Help"               att!mtune!jrw
                  "I'm bored with this....Let's Dance!"

gt0178a@prism.gatech.EDU (BURNS,JIM) (08/31/90)

in article <842@travis.csd.harris.com>, brad@SSD.CSD.HARRIS.COM (Brad Appleton) says:
< Im still hoping for a better way though! One of the few things I 
< like that csh has over ksh, is being able to returns subsets of
< an array (a la $argv[5-8], $argv[-3], $argv[4-]) but I still dont
< think csh had an "easy" way of getting just the last argument.

${argv[$#argv]}, since csh arrays start from 1. Argv[] is predefined as
the command args, and $argv = $*.
-- 
BURNS,JIM
Georgia Institute of Technology, Box 30178, Atlanta Georgia, 30332
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a
Internet: gt0178a@prism.gatech.edu

cudcv@warwick.ac.uk (Rob McMahon) (08/31/90)

In article <1990Aug18.141141.24890@warwick.ac.uk>, I said:
| I know ksh has `set -A array', but does it have an equivalent of "$@" for
| arrays other than the positional paramters ?  We don't have ksh, and can't
| afford to get it, but when bash gets a bit more solid I will switch to it if
| it has an equivalent of csh's $array:q.

In article <842@travis.csd.harris.com> brad@SSD.CSD.HARRIS.COM (Brad Appleton) writes:
|set -A argv "$@"    ## dump positional parameters into an array
|...
|from here on in you can use ${argv[i]} instead of $i and 
|${argv[*]} (${argv[@]}) in place of $* ($@).

Aha!  Does this mean that ksh *does* have a way of doing csh's $array:q,
"${array[@]}" ?  The only response I had before was that it didn't.  Sadly
I've just discovered that the current version of bash doesn't even have `set
-A' (yet ?).  Sounds like time for a posting to gnu.bash.bug.

Enquiring minds ... oh forget it.

Rob
--
UUCP:   ...!mcsun!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             INET:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

cudcv@warwick.ac.uk (Rob McMahon) (08/31/90)

In article <1992@hsi86.hsi.UUCP> kenney@hsi.com (Brian Kenney) writes:
>In article <b4CC02oVc3Jx01@amdahl.uts.amdahl.com> jonc@amdahl.uts.amdahl.com (Jonathan Chang) writes:
> 
>>How can I extract the last argument to a ksh script?
>>Example:
>>	myscript arg1 arg2 arg3
>
>args=$*
>arg3=${args##* }
>
>You're welcome.

Of course this breaks horribly if the last argument contains a space.
(Actually it doesn't work at all with bash, you need to escape the ` ' with a
`\', is this a bug ?)

This is one of my pet peeves.  People create files with spaces in their names
(often from packages), and I like to be able to tell them "Don't panic, just
surround the names with ''", I don't want to have to say "If you're using x or
y you can use '', but you can't use this with z because it's a shell script,
although of course it does work with w because it's a csh script."  People
shouldn't have to know how things are implemented.  (Yes, yes, I know, I
should say "just don't create files with spaces in the name :-(, but that
doesn't work for messages, the title of printer jobs, etc.)

Rob
--
UUCP:   ...!mcsun!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick             INET:   cudcv@warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England