From: David Kirkby on
I've seen alo of the following in scripts,

if [ $foo = "sun" ] && [ $bar = "moon" ] ; then

if [ "$foo" = "sun" ] && [ $bar = "moon" ] ; then

if [ "x$foo" = "xsun" ] && [ "x$bar" = "xmoon" ] ; then

if [ x$foo = "xsun" ] && [ x$bar = "xmoon" ] ; then

Also, sometime { and } are used.

What is the best way to compare things in shell scripts?
From: David W. Hodgins on
On Fri, 08 Jan 2010 01:59:35 -0500, David Kirkby <drkirkby(a)gmail.com> wrote:

> What is the best way to compare things in shell scripts?

Always quote variables, unless you have a good reason not to.

See http://tldp.org/LDP/abs/html/comparison-ops.html

Regards, Dave Hodgins

--
Change nomail.afraid.org to ody.ca to reply by email.
(nomail.afraid.org has been set up specifically for
use in usenet. Feel free to use it yourself.)
From: Stephane CHAZELAS on
2010-01-7, 22:59(-08), David Kirkby:
> I've seen alo of the following in scripts,
>
> if [ $foo = "sun" ] && [ $bar = "moon" ] ; then
>
> if [ "$foo" = "sun" ] && [ $bar = "moon" ] ; then
>
> if [ "x$foo" = "xsun" ] && [ "x$bar" = "xmoon" ] ; then
>
> if [ x$foo = "xsun" ] && [ x$bar = "xmoon" ] ; then
>
> Also, sometime { and } are used.
>
> What is the best way to compare things in shell scripts?

They are all wrong except for the 3rd as quotes are placed where
they're not necessary (arguments containing no special
characters) and not where they are necessary (around variables
to avoid special expansion (word splitting and globbing)).

[ "$foo" = sun ] && [ "$bar" = moon ]

will work in POSIX shells,

[ sun = "$foo" ] && [ moon = "$bar" ]
[ "x$foo" = xsun ] && [ "x$bar" = xmoon ]
[ sunmoon = "$foo$bar" ]
[ "x$foo$bar" = sunmoon ]

will work in all shells.

--
St�phane
From: Geoff Clare on
Stephane CHAZELAS wrote:

> [ "$foo" = sun ] && [ "$bar" = moon ]
>
> will work in POSIX shells,
>
> [ sun = "$foo" ] && [ moon = "$bar" ]
> [ "x$foo" = xsun ] && [ "x$bar" = xmoon ]
> [ sunmoon = "$foo$bar" ]
> [ "x$foo$bar" = sunmoon ]
>
> will work in all shells.

The last two will produce false positives if, for example,
foo=s and bar=unmoon. (Assuming the last is fixed to have
xsunmoon on the rhs.)

--
Geoff Clare <netnews(a)gclare.org.uk>


From: David Kirkby on
On Jan 8, 8:21 am, Stephane CHAZELAS <stephane_chaze...(a)yahoo.fr>
wrote:
> 2010-01-7, 22:59(-08), David Kirkby:
>
> > I've seen alo of the following in scripts,
>
> > if [ $foo = "sun" ]  && [  $bar = "moon"  ] ; then
>
> > if [ "$foo" = "sun" ]  && [ $bar = "moon" ] ; then
>
> > if [ "x$foo" = "xsun" ]  && [ "x$bar" = "xmoon" ] ; then
>
> > if [ x$foo = "xsun" ]  && [  x$bar = "xmoon" ] ; then
>
> > Also, sometime {  and } are used.
>
> > What is the best way to compare things in shell scripts?
>
> They are all wrong except for the 3rd as quotes are placed where
> they're not necessary (arguments containing no special
> characters) and not where they are necessary (around variables
> to avoid special expansion (word splitting and globbing)).
>
> [ "$foo" = sun ] && [ "$bar" = moon ]
>
> will work in POSIX shells,
>
> [ sun = "$foo" ] && [ moon = "$bar" ]
> [ "x$foo" = xsun ] && [ "x$bar" = xmoon ]
> [ sunmoon = "$foo$bar" ]
> [ "x$foo$bar" = sunmoon ]
>
> will work in all shells.
>
> --
> Stéphane

Thank you Stephane. I wonder if you could answer the following
questions, as I'm puzzled why a script is not working as I believe it
should.

1) Can you tell me if the following is perfectly safe:

if [ ! -x "$SAGE_LOCAL/bin/testcc.sh" ] || [ ! -x "$SAGE_LOCAL/bin/
testcxx.sh" ] ; then
echo "testcc.sh and/or testcxx.sh either do not exist, or are not
executable"
exit 1
fi

$SAGE_LOCAL is a directory (in my case /export/home/drkirkby/
sage-4.3.1.alpha1/local). I happen to know that $SAGE_LOCAL will have
no spaces in it, but in general would the above work if the path has
spaces? Let's for example assume it was "/export/home/drkirkby/this is
an alpha release of sage 4.3.1". Can I be sure the above will always
work?

Is:

if [ ! -x ""$SAGE_LOCAL"/bin/testcc.sh" ] || [ ! -x ""$SAGE_LOCAL"/bin/
testcxx.sh" ] ; then
echo "testcc.sh and/or testcxx.sh either do not exist, or are not
executable"
exit 1
fi

better or not? If not, is there a better way, and if so how? (By
better, I want something that has the best probability of working in
any shell - bash, POSIX and preferably some of the more common non-
POSIX shells, though I appreciate one can't cover every possibility
there.)

2) As you might guess from the names, the scripts test the C and C++
compilers. They do it by detecting what macros are predefined. I do
happen to know the scripts will only print something without a space
(either GCC, Sun_Studio, HP_on_Tru64, HP_on_HP-UX, IBM_on_AIX,
HP_on_Alpha_Linux or Unknown). But in general, lets assume I did not
know this fact. How should I test if the two scripts are printing the
same thing?

If I run them at the command line:

drkirkby(a)hawk:~/sage-4.3.1.alpha1$ echo $CC
cc
drkirkby(a)hawk:~/sage-4.3.1.alpha1$ echo $CXX
CC
drkirkby(a)hawk:~/sage-4.3.1.alpha1$ local/bin/testcc.sh $CC
Sun_Studio
drkirkby(a)hawk:~/sage-4.3.1.alpha1$ local/bin/testcxx.sh $CXX
Sun_Studio

I tried to set two variables like this:

C_compiler=`"$(SAGE_LOCAL)"/bin/testcc.sh $CC`
C_PLUS_PLUS_compiler=`"$(SAGE_LOCAL)"/bin/testcxx.sh $CXX`


but that results in errors when the script is run.

/export/home/drkirkby/sage-4.3.1.alpha1/local/bin/sage-spkg: line 317:
SAGE_LOCAL: command not found
/export/home/drkirkby/sage-4.3.1.alpha1/local/bin/sage-spkg: line
317: /bin/testcc.sh: No such file or directory
/export/home/drkirkby/sage-4.3.1.alpha1/local/bin/sage-spkg: line 318:
SAGE_LOCAL: command not found
/export/home/drkirkby/sage-4.3.1.alpha1/local/bin/sage-spkg: line
318: /bin/testcxx.sh: No such file or directory


C_compiler="`$(SAGE_LOCAL)/bin/testcc.sh $CC`"
C_PLUS_PLUS_compiler="`$(SAGE_LOCAL)/bin/testcxx.sh $CXX`"

does not work. Neither does

C_compiler="`"$(SAGE_LOCAL)"/bin/testcc.sh $CC`"
C_PLUS_PLUS_compiler="`"$(SAGE_LOCAL)"/bin/testcxx.sh $CXX`"

The only thing I've found to semi work is:

C_compiler=`$SAGE_LOCAL/bin/testcc.sh $CC`
C_PLUS_PLUS_compiler=`$SAGE_LOCAL/bin/testcxx.sh $CXX`

but I'm concerned that in general that might not be reliable if
SAGE_LOCAL had spaces or other difficult characters.

Any ideas of the best way to do this?

3) Using

C_compiler=`$SAGE_LOCAL/bin/testcc.sh $CC`
C_PLUS_PLUS_compiler=`$SAGE_LOCAL/bin/testcxx.sh $CXX`
# Exit if there are a mixture of compilers.
if [ "$C_compiler" != "$C_PLUS_PLUS_compiler" ] ; then
echo ""
echo "ERROR: You have different C and C++ compilers."
echo "ERROR The C compiler is $C_compiler, the C++ compiler is
$C_PLUS_PLUS_compiler"
echo "ERROR: This mixture can not be used to build Sage"
echo "ERROR: Ensure both compilers are the same"
exit 1
fi

fails to produce the expected result, as the output from the script
is:

ERROR: You have different C and C++ compilers.
ERROR The C compiler is Sun_Studio, the C++ compiler is Sun_Studio
ERROR: This mixture can not be used to build Sage
ERROR: Ensure both compilers are the same

Any thoughts on how I can make this bullet proof?