old-www/LDP/abs/html/comparison-ops.html

1217 lines
16 KiB
HTML
Raw Permalink Blame History

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Other Comparison Operators</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Advanced Bash-Scripting Guide"
HREF="index.html"><LINK
REL="UP"
TITLE="Tests"
HREF="tests.html"><LINK
REL="PREVIOUS"
TITLE="File test operators"
HREF="fto.html"><LINK
REL="NEXT"
TITLE="Nested if/then Condition Tests"
HREF="nestedifthen.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Advanced Bash-Scripting Guide: </TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="fto.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 7. Tests</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="nestedifthen.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="COMPARISON-OPS"
></A
>7.3. Other Comparison Operators</H1
><P
>A <I
CLASS="FIRSTTERM"
>binary</I
> comparison operator
compares two variables or quantities. <EM
>Note
that integer and string comparison use a different set of
operators.</EM
></P
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="ICOMPARISON1"
></A
>integer comparison</B
></P
><DL
><DT
><A
NAME="EQUALREF"
></A
><SPAN
CLASS="TOKEN"
>-eq</SPAN
></DT
><DD
><P
>is equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -eq "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="NEQUALREF"
></A
><SPAN
CLASS="TOKEN"
>-ne</SPAN
></DT
><DD
><P
>is not equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -ne "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="GT0REF"
></A
><SPAN
CLASS="TOKEN"
>-gt</SPAN
></DT
><DD
><P
>is greater than</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -gt "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="GE0REF"
></A
><SPAN
CLASS="TOKEN"
>-ge</SPAN
></DT
><DD
><P
>is greater than or equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -ge "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="LT0REF"
></A
><SPAN
CLASS="TOKEN"
>-lt</SPAN
></DT
><DD
><P
>is less than</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -lt "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="LE0REF"
></A
><SPAN
CLASS="TOKEN"
>-le</SPAN
></DT
><DD
><P
>is less than or equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" -le "$b" ]</B
></TT
></P
></DD
><DT
><A
NAME="INTLT"
></A
><SPAN
CLASS="TOKEN"
>&#60;</SPAN
></DT
><DD
><P
>is less than (within <A
HREF="dblparens.html"
>double
parentheses</A
>)</P
><P
><TT
CLASS="USERINPUT"
><B
>(("$a" &#60; "$b"))</B
></TT
></P
></DD
><DT
><A
NAME="LTEQ"
></A
><SPAN
CLASS="TOKEN"
>&#60;=</SPAN
></DT
><DD
><P
>is less than or equal to (within double parentheses)</P
><P
><TT
CLASS="USERINPUT"
><B
>(("$a" &#60;= "$b"))</B
></TT
></P
></DD
><DT
><A
NAME="INTGT"
></A
><SPAN
CLASS="TOKEN"
>&#62;</SPAN
></DT
><DD
><P
>is greater than (within double parentheses)</P
><P
><TT
CLASS="USERINPUT"
><B
>(("$a" &#62; "$b"))</B
></TT
></P
></DD
><DT
><A
NAME="GTEQ"
></A
><SPAN
CLASS="TOKEN"
>&#62;=</SPAN
></DT
><DD
><P
>is greater than or equal to (within double parentheses)</P
><P
><TT
CLASS="USERINPUT"
><B
>(("$a" &#62;= "$b"))</B
></TT
></P
></DD
></DL
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="SCOMPARISON1"
></A
>string comparison</B
></P
><DL
><DT
><SPAN
CLASS="TOKEN"
>=</SPAN
></DT
><DD
><P
><A
NAME="EQUALSIGNREF"
></A
></P
><P
>is equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" = "$b" ]</B
></TT
></P
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>Note the <A
HREF="special-chars.html#WHITESPACEREF"
>whitespace</A
>
framing the <B
CLASS="COMMAND"
>=</B
>.</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a"="$b" ]</B
></TT
> is
<EM
>not</EM
> equivalent to the
above.</P
></TD
></TR
></TABLE
></DIV
></DD
><DT
><A
NAME="SCOMPARISON2"
></A
><SPAN
CLASS="TOKEN"
>==</SPAN
></DT
><DD
><P
>is equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" == "$b" ]</B
></TT
></P
><P
>This is a synonym for <SPAN
CLASS="TOKEN"
>=</SPAN
>.</P
><DIV
CLASS="NOTE"
><P
></P
><TABLE
CLASS="NOTE"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/note.gif"
HSPACE="5"
ALT="Note"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
> The <SPAN
CLASS="TOKEN"
>==</SPAN
> comparison operator behaves differently
within a <A
HREF="testconstructs.html#DBLBRACKETS"
>double-brackets</A
>
test than within single brackets.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
# Thanks, St<53>phane Chazelas</PRE
></FONT
></TD
></TR
></TABLE
>
</P
></TD
></TR
></TABLE
></DIV
></DD
><DT
><A
NAME="NOTEQUAL"
></A
><SPAN
CLASS="TOKEN"
>!=</SPAN
></DT
><DD
><P
>is not equal to</P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" != "$b" ]</B
></TT
></P
><P
>This operator uses pattern matching within a <A
HREF="testconstructs.html#DBLBRACKETS"
>[[ ... ]]</A
> construct.</P
></DD
><DT
><A
NAME="LTREF"
></A
><SPAN
CLASS="TOKEN"
>&#60;</SPAN
></DT
><DD
><P
>is less than, in <A
HREF="special-chars.html#ASCIIDEF"
>ASCII</A
> alphabetical
order</P
><P
><TT
CLASS="USERINPUT"
><B
>if [[ "$a" &#60; "$b" ]]</B
></TT
></P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" \&#60; "$b" ]</B
></TT
></P
><P
>Note that the <SPAN
CLASS="QUOTE"
>"&#60;"</SPAN
> needs to be
<A
HREF="escapingsection.html#ESCP"
>escaped</A
> within a
<TT
CLASS="USERINPUT"
><B
>[ ]</B
></TT
> construct.</P
></DD
><DT
><A
NAME="GTREF"
></A
><SPAN
CLASS="TOKEN"
>&#62;</SPAN
></DT
><DD
><P
>is greater than, in ASCII alphabetical order</P
><P
><TT
CLASS="USERINPUT"
><B
>if [[ "$a" &#62; "$b" ]]</B
></TT
></P
><P
><TT
CLASS="USERINPUT"
><B
>if [ "$a" \&#62; "$b" ]</B
></TT
></P
><P
>Note that the <SPAN
CLASS="QUOTE"
>"&#62;"</SPAN
> needs to be
escaped within a <TT
CLASS="USERINPUT"
><B
>[ ]</B
></TT
> construct.</P
><P
>See <A
HREF="arrays.html#BUBBLE"
>Example 27-11</A
> for an application of this
comparison operator.</P
></DD
><DT
><A
NAME="STRINGNULL"
></A
><SPAN
CLASS="TOKEN"
>-z</SPAN
></DT
><DD
><P
>string is <I
CLASS="FIRSTTERM"
>null</I
>,
that is, has zero length</P
><P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
> String='' # Zero-length ("null") string variable.
if [ -z "$String" ]
then
echo "\$String is null."
else
echo "\$String is NOT null."
fi # $String is null.</PRE
></FONT
></TD
></TR
></TABLE
></P
></DD
><DT
><A
NAME="STRINGNOTNULL"
></A
><SPAN
CLASS="TOKEN"
>-n</SPAN
></DT
><DD
><P
>string is not <I
CLASS="FIRSTTERM"
>null.</I
></P
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The <TT
CLASS="USERINPUT"
><B
>-n</B
></TT
> test
requires that the string be quoted within the
test brackets. Using an unquoted string with
<I
CLASS="FIRSTTERM"
>! -z</I
>, or even just the
unquoted string alone within test brackets (see <A
HREF="comparison-ops.html#STRTEST"
>Example 7-6</A
>) normally works, however, this is
an unsafe practice. <EM
>Always</EM
> quote
a tested string.
<A
NAME="AEN3669"
HREF="#FTN.AEN3669"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
>
</P
></TD
></TR
></TABLE
></DIV
></DD
></DL
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="EX13"
></A
><P
><B
>Example 7-5. Arithmetic and string comparisons</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
a=4
b=5
# Here "a" and "b" can be treated either as integers or strings.
# There is some blurring between the arithmetic and string comparisons,
#+ since Bash variables are not strongly typed.
# Bash permits integer operations and comparisons on variables
#+ whose value consists of all-integer characters.
# Caution advised, however.
echo
if [ "$a" -ne "$b" ]
then
echo "$a is not equal to $b"
echo "(arithmetic comparison)"
fi
echo
if [ "$a" != "$b" ]
then
echo "$a is not equal to $b."
echo "(string comparison)"
# "4" != "5"
# ASCII 52 != ASCII 53
fi
# In this particular instance, both "-ne" and "!=" work.
echo
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="STRTEST"
></A
><P
><B
>Example 7-6. Testing whether a string is <I
CLASS="FIRSTTERM"
>null</I
></B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# str-test.sh: Testing null strings and unquoted strings,
#+ but not strings and sealing wax, not to mention cabbages and kings . . .
# Using if [ ... ]
# If a string has not been initialized, it has no defined value.
# This state is called "null" (not the same as zero!).
if [ -n $string1 ] # string1 has not been declared or initialized.
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # Wrong result.
# Shows $string1 as not null, although it was not initialized.
echo
# Let's try it again.
if [ -n "$string1" ] # This time, $string1 is quoted.
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # Quote strings within test brackets!
echo
if [ $string1 ] # This time, $string1 stands naked.
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # This works fine.
# The [ ... ] test operator alone detects whether the string is null.
# However it is good practice to quote it (if [ "$string1" ]).
#
# As Stephane Chazelas points out,
# if [ $string1 ] has one argument, "]"
# if [ "$string1" ] has two arguments, the empty "$string1" and "]"
echo
string1=initialized
if [ $string1 ] # Again, $string1 stands unquoted.
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # Again, gives correct result.
# Still, it is better to quote it ("$string1"), because . . .
string1="a = b"
if [ $string1 ] # Again, $string1 stands unquoted.
then
echo "String \"string1\" is not null."
else
echo "String \"string1\" is null."
fi # Not quoting "$string1" now gives wrong result!
exit 0 # Thank you, also, Florian Wisser, for the "heads-up".</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="EX14"
></A
><P
><B
>Example 7-7. <I
CLASS="FIRSTTERM"
>zmore</I
></B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# zmore
# View gzipped files with 'more' filter.
E_NOARGS=85
E_NOTFOUND=86
E_NOTGZIP=87
if [ $# -eq 0 ] # same effect as: if [ -z "$1" ]
# $1 can exist, but be empty: zmore "" arg2 arg3
then
echo "Usage: `basename $0` filename" &#62;&#38;2
# Error message to stderr.
exit $E_NOARGS
# Returns 85 as exit status of script (error code).
fi
filename=$1
if [ ! -f "$filename" ] # Quoting $filename allows for possible spaces.
then
echo "File $filename not found!" &#62;&#38;2 # Error message to stderr.
exit $E_NOTFOUND
fi
if [ ${filename##*.} != "gz" ]
# Using bracket in variable substitution.
then
echo "File $1 is not a gzipped file!"
exit $E_NOTGZIP
fi
zcat $1 | more
# Uses the 'more' filter.
# May substitute 'less' if desired.
exit $? # Script returns exit status of pipe.
# Actually "exit $?" is unnecessary, as the script will, in any case,
#+ return the exit status of the last command executed.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="CCOMPARISON1"
></A
>compound comparison</B
></P
><DL
><DT
><A
NAME="COMPOUNDAND"
></A
><SPAN
CLASS="TOKEN"
>-a</SPAN
></DT
><DD
><P
>logical and</P
><P
><TT
CLASS="REPLACEABLE"
><I
>exp1 -a exp2</I
></TT
> returns true if
<EM
>both</EM
> exp1 and exp2 are true.</P
></DD
><DT
><A
NAME="COMPOUNDOR"
></A
><SPAN
CLASS="TOKEN"
>-o</SPAN
></DT
><DD
><P
>logical or </P
><P
><TT
CLASS="REPLACEABLE"
><I
>exp1 -o exp2</I
></TT
> returns
true if either exp1 <EM
>or</EM
> exp2 is
true.</P
></DD
></DL
></DIV
><P
> These are similar to the Bash comparison operators
<B
CLASS="COMMAND"
>&#38;&#38;</B
> and <B
CLASS="COMMAND"
>||</B
>, used
within <A
HREF="testconstructs.html#DBLBRACKETS"
>double brackets</A
>.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>[[ condition1 &#38;&#38; condition2 ]]</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
> The <B
CLASS="COMMAND"
>-o</B
> and <B
CLASS="COMMAND"
>-a</B
> operators
work with the <A
HREF="testconstructs.html#TTESTREF"
>test</A
> command or
occur within single test brackets.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>if [ "$expr1" -a "$expr2" ]
then
echo "Both expr1 and expr2 are true."
else
echo "Either expr1 or expr2 is false."
fi</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>But, as <EM
>rihad</EM
> points out:
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>[ 1 -eq 1 ] &#38;&#38; [ -n "`echo true 1&#62;&#38;2`" ] # true
[ 1 -eq 2 ] &#38;&#38; [ -n "`echo true 1&#62;&#38;2`" ] # (no output)
# ^^^^^^^ False condition. So far, everything as expected.
# However ...
[ 1 -eq 2 -a -n "`echo true 1&#62;&#38;2`" ] # true
# ^^^^^^^ False condition. So, why "true" output?
# Is it because both condition clauses within brackets evaluate?
[[ 1 -eq 2 &#38;&#38; -n "`echo true 1&#62;&#38;2`" ]] # (no output)
# No, that's not it.
# Apparently &#38;&#38; and || "short-circuit" while -a and -o do not.</PRE
></FONT
></TD
></TR
></TABLE
>
</P
></TD
></TR
></TABLE
></DIV
><P
>Refer to <A
HREF="ops.html#ANDOR"
>Example 8-3</A
>, <A
HREF="arrays.html#TWODIM"
>Example 27-17</A
>,
and <A
HREF="contributed-scripts.html#WHX"
>Example A-29</A
> to see compound comparison operators
in action.</P
></DIV
><H3
CLASS="FOOTNOTES"
>Notes</H3
><TABLE
BORDER="0"
CLASS="FOOTNOTES"
WIDTH="100%"
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="5%"
><A
NAME="FTN.AEN3669"
HREF="comparison-ops.html#AEN3669"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>As S.C. points out, in a compound test,
even quoting the string variable might not
suffice. <TT
CLASS="USERINPUT"
><B
>[ -n "$string" -o "$a" = "$b" ]</B
></TT
>
may cause an error with some versions of Bash if
<TT
CLASS="VARNAME"
>$string</TT
> is empty. The safe way
is to append an extra character to possibly empty variables,
<TT
CLASS="USERINPUT"
><B
>[ "x$string" != x -o "x$a" = "x$b" ]</B
></TT
>
(the <SPAN
CLASS="QUOTE"
>"x's"</SPAN
> cancel out).</P
></TD
></TR
></TABLE
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="fto.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="nestedifthen.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>File test operators</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="tests.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Nested <TT
CLASS="REPLACEABLE"
><I
>if/then</I
></TT
> Condition Tests</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>