Unix Shell - Testing for a particular parameter without looping

This is Interesting: Free IT Magazines  
Home > Archive > Unix Shell > October 2004 > Testing for a particular parameter without looping





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Testing for a particular parameter without looping
Timur Tabi

2004-10-04, 6:01 pm

I have a bash script that can get passed any number of different
parameters. At one point, I need to test if a particular parameter
has been passed. For example, the script could be called by "myscript
A B C", or it could be called by "myscript B C A". All I care about
is if "B" was passed.

I know I can do this with a loop, checking each parameter, but I was
wondering if it can be done without a loop, and preferably without
calling an external program (like awk). Any ideas?
Bit Twister

2004-10-04, 6:01 pm

On 4 Oct 2004 16:01:38 -0700, Timur Tabi wrote:
> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter
> has been passed. For example, the script could be called by "myscript
> A B C", or it could be called by "myscript B C A". All I care about
> is if "B" was passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


use _if_ statements
Bob

2004-10-04, 8:47 pm

On Mon, 04 Oct 2004 16:01:38 -0700, Timur Tabi wrote:

> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter has
> been passed. For example, the script could be called by "myscript A B C",
> or it could be called by "myscript B C A". All I care about is if "B" was
> passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without calling
> an external program (like awk). Any ideas?


Here is something that works if all parameters are single characters. Only
lightly tested -- may have bugs or make unwarranted assumptions!

=================================
#!/bin/bash

p="C" # variable p is set to parameter to look for

if [ "${*/$p/}" != "$*" ] ; then
echo "$p seen"
else
echo "$p not seen"
fi
=================================


Seb

2004-10-04, 8:47 pm

On 2004-10-05, Bob <bob@dont.spam.me> wrote:
> Here is something that works if all parameters are single characters. Only
> lightly tested -- may have bugs or make unwarranted assumptions!
>
> =================================
> #!/bin/bash
>
> p="C" # variable p is set to parameter to look for
>
> if [ "${*/$p/}" != "$*" ] ; then
> echo "$p seen"
> else
> echo "$p not seen"
> fi
> =================================


For non-single characters, following the same idea, one could do:

p="theOption" # variable p is set to parameter to look for

if [ "${*/ $p /}" != "$*" ] ; then
echo "$p seen"
else
echo "$p not seen"
fi

--Seb
William Park

2004-10-04, 8:47 pm

Timur Tabi <nospam_timur@tabi.org> wrote:
> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter
> has been passed. For example, the script could be called by "myscript
> A B C", or it could be called by "myscript B C A". All I care about
> is if "B" was passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


Not in standard shell. With my patch to Bash shell,
${*|/B}
${@|/B}
will return positional parameters matching glob pattern 'B'.

Ref:
http://freshmeat.net/projects/bashdiff/
--
William Park <opengeometry@yahoo.ca>
Open Geometry Consulting, Toronto, Canada
Bob

2004-10-05, 3:01 am

On Tue, 05 Oct 2004 02:10:27 +0000, Seb wrote:

> On 2004-10-05, Bob <bob@dont.spam.me> wrote:
>
> For non-single characters, following the same idea, one could do:
>
> p="theOption" # variable p is set to parameter to look for
>
> if [ "${*/ $p /}" != "$*" ] ; then
> echo "$p seen"
> else
> echo "$p not seen"
> fi
>
> --Seb


Need to account for the optoin being first or last:

p="theOPtion"

opts=" $* "
if [ "${opts/ $p /}" != "$opts" ] ; then
<the rest as above>

Warning *totally* untested!

Ed Morton

2004-10-05, 3:01 am



Timur Tabi wrote:
> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter
> has been passed. For example, the script could be called by "myscript
> A B C", or it could be called by "myscript B C A". All I care about
> is if "B" was passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


This will work if all your parameters are single-character and take no
arguments that might contain a "B":

case $* in
*B* ) echo "Eureka!" ;;
* ) echo "boo hoo..." ;;
esac

Regards,

Ed.
Stephane CHAZELAS

2004-10-05, 3:01 am

2004-10-04, 22:15(-05), Ed Morton:
[...]
> case $* in
> *B* ) echo "Eureka!" ;;
> * ) echo "boo hoo..." ;;
> esac

[...]

That tests wether the concatenation (with spaces unless IFS was
modified) of the arguments contains "B", not wether there's a
"B" amongst the arguments

With zsh:

if (( $+argv[(r)B] )); then
echo "Eureka!"
else
echo "boo hoo..."
fi

There's no equivalent with bash, unless you're ready to suppose
that one particular character is not present in the arguments:

If it's "|":

IFS="|"
case "|$*|" in
*"|B|"*) echo yes;;
*) echo no;;
esac

--
Stephane
Bill Marcum

2004-10-05, 5:58 pm

On 4 Oct 2004 16:01:38 -0700, Timur Tabi
<nospam_timur@tabi.org> wrote:
> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter
> has been passed. For example, the script could be called by "myscript
> A B C", or it could be called by "myscript B C A". All I care about
> is if "B" was passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


case "$*" in
B *|* B *|* B) echo "script has B" ;;
esac

--
System Events
=-=-=-=-=-=-=
Sep 16 03:31:11 don kernel: lp0 on fire

Stephane CHAZELAS

2004-10-05, 5:58 pm

2004-10-5, 07:15(-04), Bill Marcum:
[...]
> case "$*" in
> B *|* B *|* B) echo "script has B" ;;
> esac


~$ case "$*" in
case> B *|* B *|* B) echo "script has B" ;;
zsh: parse error near `*'
bash: syntax error near unexpected token `*'
esac> ksh: syntax error: `*' unexpected
esac> syntax error: `*' unexpected


Should be:

case "$*" in
B\ *|*\ B\ *|*\ B) echo "script has B" ;;
esac

But that works only for Bourne shell or with POSIX shells if IFS
is unset or starts with " ".

It's not reliable if arguments may contain spaces.

It can be shortened as:

case " $* " in
*" B "*) echo "script has B" ;;
esac

Actually, with bash and ksh93 (not zsh), you can do it as:

IFS=,
case ",${*//,/}," in
*,B,*) echo script has B;;
esac

Of course, that doesn't work if instead of "B", you have a
string with commas in it (but you could use an other character
then as first character of IFS).

I guess you shouldn't rely on that behavior as it's not the
behavior one would expect (at least by Bourne standard, $* is
supposed to be a normal parameter whose value is the
concatenation of the arguments with first character of IFS
inbetween, so that ${*//,/} shouldn't contain any ",").

--
Stephane
Ed Morton

2004-10-05, 5:58 pm



Stephane CHAZELAS wrote:
> 2004-10-04, 22:15(-05), Ed Morton:
> [...]
>
>
> [...]
>
> That tests wether the concatenation (with spaces unless IFS was
> modified) of the arguments contains "B", not wether there's a
> "B" amongst the arguments


That's right. Hence the caveat I stated in the part you snipped.

Ed.
Stephane CHAZELAS

2004-10-05, 5:58 pm

2004-10-05, 07:52(-05), Ed Morton:
[...]
>
> That's right. Hence the caveat I stated in the part you snipped.

[...]

Oops, sorry. I was reading too fast.

--
Stephane
Ed Morton

2004-10-05, 5:58 pm



Stephane CHAZELAS wrote:
> 2004-10-05, 07:52(-05), Ed Morton:
> [...]
>
>
> [...]
>
> Oops, sorry. I was reading too fast.
>


No problem. By the way - hope you've settled in and are enjoying the
weather in sunny Scotland. I just got back from a 2-week trip there and
found the rain slightly warmer than I remembered ;-).

Ed.
Dana French

2004-10-05, 5:58 pm

nospam_timur@tabi.org (Timur Tabi) wrote in message news:<53bb806a.0410041501.d402b72@posting.google.com>...
> I have a bash script that can get passed any number of different
> parameters. At one point, I need to test if a particular parameter
> has been passed. For example, the script could be called by "myscript
> A B C", or it could be called by "myscript B C A". All I care about
> is if "B" was passed.
>
> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


A ksh93 solution (assumes command line options do NOT contain a colon):

IFS=":"
[[ "${*}" = @(B:*|*:B:*|*:B) ]] && print "B was passed"


--------------------------------------------------------
Dana French dfrench@mtxia.com
Mt Xia Technical Consulting Group http://www.mtxia.com
100% Spam Free Email http://www.ridmail.com
MicroEmacs http://uemacs.tripod.com
Korn Shell Web http://dfrench.tripod.com/kshweb.html
Stephen Riehm

2004-10-05, 5:58 pm

Timur Tabi wrote:

> I know I can do this with a loop, checking each parameter, but I was
> wondering if it can be done without a loop, and preferably without
> calling an external program (like awk). Any ideas?


Is there a reason for not using a loop?
I know that loops are slow etc., but in this case you're looping through
maybe 100 values, probably less than 10 - efficiency should not be a
concern. The solutions which run a regular expression over $* also
result in a loop, you just can't see it through all those cryptic
characters ;-) (don't lecture me, I know what they mean, it's called
"humor")

If you're looking for clarity, then I would suggest you loop through the
options once at the beginning of your script, and pull out the things
you're likely to need later on. Store them in simple variables. e.g.
$arg_a, $arg_b etc. Then, when you need to check if B was set, simply
refer to $arg_b. Another advantage of doing something like this is that
you can put your consistency checking (preventing conflicting
combinations of options, or automatically setting $verbose if you turned
on debugging etc).

Just a different slant on the problem.

Steve
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com