DaemonForums  

Go Back   DaemonForums > Miscellaneous > Programming

Programming C, bash, Python, Perl, PHP, Java, you name it.

Reply
 
Thread Tools Display Modes
  #1   (View Single Post)  
Old 31st December 2015
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 4,128
Default Comparing strings with the shell

From test(1):
Code:
 s1 = s2
    True if the strings s1 and s2 are identical.
s1 != s2
    True if the strings s1 and s2 are not identical.
s1 < s2
    True if string s1 comes before s2 based on the ASCII value of their characters.
s1 > s2
    True if string s1 comes after s2 based on the ASCII value of their characters.
So here we go .....
Code:
$ if [ 'aaa' < 'aab' ] ; then echo stringwise smaller ; fi
ksh: cannot open aab: No such file or directory
Ok the '<' in the shell means to take the contents of file 'aab' and use it as input. So we escape the '<' ...
Code:
$ if [ 'aaa' \< 'aab' ] ; then echo stringwise smaller ; fi
ksh: [: <: unexpected operator/operand
Yes, this is OpenBSD and the standard shell is ksh(1) .... Obviously the escaping does not work here.

Then I remember that shells have built-in's commands that sometimes behave differently than the ones residing in /bin/ for example. Checking the shell test command From ksh(1):
Code:
test expression
[ expression ]
        test evaluates the expression and returns zero status if true, 1
        if false, or greater than 1 if there was an error.  It is
        normally used as the condition command of if and while
        statements. 
[snip]
        -n string          string is not empty.

        -z string          string is empty.

        string = string    Strings are equal.

        string == string   Strings are equal.

        string != string   Strings are not equal

        number -eq number  Numbers compare equal.
Notice that the string comparison operators < and > are missing.
The /bin/test executable instead of the ksh one works with escaping the '<':
Code:
$ if  /bin/test "aap" \< "aap2" ; then echo Smaller! ; fi
Smaller!
If you forget to escape the shell output redirector ">" then ....
Code:
$ if  /bin/test "aap2" > "aap" ; then echo Larger! ; fi   
Larger!
$ if  /bin/test "aap" > "aap" ; then echo Larger! ; fi   
Larger!
$ ls -l aap
-rw-r--r--  1 adriaan  adriaan  0 Dec 31 02:05 aap
With an escape it works:
Code:
$  if  /bin/test "aap" \> "aap" ; then echo Larger! ; fi
$
Yes, this has cost me some headache to figure out .....
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump
Reply With Quote
  #2   (View Single Post)  
Old 31st December 2015
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 4,128
Default

Two demo shell scripts that show the problem as well as the solution. The problematic one stringwise_less.sh:
Code:
 #!/bin/sh

#set -o posix

if [ "X$1" = "X" ]; then
   prev_date="20151229"
else
   prev_date="$1"
fi

cur_date=$(date "+%Y-%m-%d")
cur_date=$(date "+%Y%m%d")

show() {
   echo
   echo "Previous date : [$prev_date]"
   echo "Current date  : [$cur_date]"
   cat <<END
-----file list-------------------------------------
$(ls -ltr)
---------------------------------------------------
END
}

if [ "$prev_date" < "$cur_date" ]; then
   show
   echo "Previous date [$prev_date] < current date [$cur_date]"
fi
 
if [ "$prev_date" = "$cur_date" ]; then
   show
   echo "Previous date [$prev_date] = current date [$cur_date]"
fi

 
if [ "$prev_date" > "$cur_date" ]; then
   show
   echo "Previous date [$prev_date] > current date [$cur_date]"
fi
Running the script:
Code:
$ stringwise_less.sh 20141231                              
./stringwise_less.sh[28]: cannot open 20151231: No such file or directory

Previous date : [20141231]
Current date  : [20151231]
-----file list-------------------------------------
total 8
-rwxr--r--  1 adriaan  adriaan  739 Dec 30 23:59 stringwise_less.sh
-rwxr--r--  1 adriaan  adriaan  764 Dec 31 01:24 stringwise_less2.sh
-rw-r--r--  1 adriaan  adriaan    0 Dec 31 02:27 20151231
---------------------------------------------------
Previous date [20141231] > current date [20151231]
$ rm 2015*
$ stringwise_less.sh 20191231 
./stringwise_less.sh[28]: cannot open 20151231: No such file or directory

Previous date : [20191231]
Current date  : [20151231]
-----file list-------------------------------------
total 8
-rwxr--r--  1 adriaan  adriaan  739 Dec 30 23:59 stringwise_less.sh
-rwxr--r--  1 adriaan  adriaan  764 Dec 31 01:24 stringwise_less2.sh
-rw-r--r--  1 adriaan  adriaan    0 Dec 31 02:29 20151231
---------------------------------------------------
Previous date [20191231] > current date [20151231]
$ date           
Thu Dec 31 02:31:58 CET 2015
$ stringwise_less.sh 20151231                              
./stringwise_less.sh[28]: cannot open 20151231: No such file or directory

Previous date : [20151231]
Current date  : [20151231]
-----file list-------------------------------------
total 8
-rwxr--r--  1 adriaan  adriaan  739 Dec 30 23:59 stringwise_less.sh
-rwxr--r--  1 adriaan  adriaan  764 Dec 31 01:24 stringwise_less2.sh
---------------------------------------------------
Previous date [20151231] = current date [20151231]

Previous date : [20151231]
Current date  : [20151231]
-----file list-------------------------------------
total 8
-rwxr--r--  1 adriaan  adriaan  739 Dec 30 23:59 stringwise_less.sh
-rwxr--r--  1 adriaan  adriaan  764 Dec 31 01:24 stringwise_less2.sh
-rw-r--r--  1 adriaan  adriaan    0 Dec 31 02:32 20151231
---------------------------------------------------
Previous date [20151231] > current date [20151231]
$
The second one, named stringwise_less2.sh solves the issue by using /bin/test. A grep(1) of the changes:
Code:
$ grep test stringwise_less2.sh  
if /bin/test "$prev_date" \< "$cur_date" ; then
if /bin/test  "$prev_date" = "$cur_date" ; then
if /bin/test  "$prev_date" \> "$cur_date" ; then
PS: A warning note lifted from the OpenBSD ksh man page:
Code:
Note: A common mistake is to use ``if [ $foo = bar ]'' which
fails if parameter ``foo'' is NULL or unset, if it has embedded
spaces (i.e. IFS characters), or if it is a unary operator like
`!' or `-n'.  Use tests like ``if [ "X$foo" = Xbar ]'' instead.
Attached Files
File Type: sh stringwise_less.sh (739 Bytes, 57 views)
File Type: sh stringwise_less2.sh (764 Bytes, 60 views)
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump

Last edited by J65nko; 31st December 2015 at 01:54 AM.
Reply With Quote
  #3   (View Single Post)  
Old 1st January 2016
drl's Avatar
drl drl is offline
Port Guard
 
Join Date: May 2008
Posts: 19
Default

Hi.

The ksh Version AJM 93u+ 2012-08-01 allows the use of [[ ... ]] which allows <,> in conditionals.

Sorry, I don't have OpenBSD accessible to me right now.

Best wishes ... cheers, drl
Reply With Quote
  #4   (View Single Post)  
Old 1st January 2016
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 4,128
Default

Yes, I know that the Korn shell [[ .... ]] constructs allows it. On OpenBSD it also does and you don't need to quote it.
Code:
$ if [[ 'zzz' > 'aaa' ]]; then echo Greater ; fi   
Greater
$ ls -l aaa
ls: aaa: No such file or directory
$ if [[ 'zzz' \> 'aaa' ]]; then echo Greater ; fi
ksh: syntax error: `"zzz"' missing expression operator
$
But that is not portable for /bin/sh of for example FreeBSD:
Code:
$ echo $SHELL
/bin/sh
$ uname
FreeBSD
$ if [[ 'zzz' > 'aaa' ]]; then echo Greater ; fi 
[[: not found
$ ls -l aaa
-rw-r--r--  1 j65nko  j65nko  0 Jan  1 16:39 aaa
$ if [ 'zzz' > 'aaa' ]; then echo Greater ; fi
Greater
$ ls -l aaa
-rw-r--r--  1 j65nko  j65nko  0 Jan  1 16:42 aaa
$ rm aaa
$ if [ 'zzz' \> 'aaa' ]; then echo Greater ; fi
Greater
$ ls -l aaa
ls: aaa: No such file or directory
$
But as you see, there the single [ ...... ] works. As stated in the FreeBSD sh(1) man page under the heading Built-in Commands:

Code:
[	     A built-in	equivalent of test(1).
OpenBSD's ksh which can be run as sh lacks the '<' and '>' string comparison of OpenBSD's /bin/[. This difference is documented in the manual pages of that shell, but I just did not realize that
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump
Reply With Quote
  #5   (View Single Post)  
Old 2nd January 2016
Carpetsmoker's Avatar
Carpetsmoker Carpetsmoker is offline
Real Name: Martin
Tcpdump Spy
 
Join Date: Apr 2008
Location: Netherlands
Posts: 2,243
Default

FYI, the < and > operators are not in POSIX
__________________
UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things.
Reply With Quote
  #6   (View Single Post)  
Old 2nd January 2016
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 4,128
Default

I tried to enable POSIX mode but disabled that with #set -o posix (see the second post) when I found the POSIX documents.
While missing from POSIX test(1), these < and > operators are in POSIX expr(1).

With Linux expr works:
Code:
$ if expr 'zzz' \> 'aaa' ; then echo Greater ; fi
Greater
But OpenBSD as well as FreeBSD, besides setting the error level, write a "1" or "0" followed by a <newline> to standard output, as mandated by POSIX :
Quote:
The expr utility shall evaluate the expression and write the result, followed by a <newline>, to standard output.
So in those BSD's you get:
Code:
$ if expr 'zzz' \> 'aaa' ; then echo Greater ; fi
1
Greater
That would mess up the output of the shell script that I was writing, unless you redirect that to /dev/null. But I found that too messy, so I sticked with /bin/test for now
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump

Last edited by J65nko; 2nd January 2016 at 06:30 PM.
Reply With Quote
  #7   (View Single Post)  
Old 3rd January 2016
IdOp's Avatar
IdOp IdOp is offline
Too dumb for a smartphone
 
Join Date: May 2008
Location: twisting on the daemon's fork(2)
Posts: 1,027
Default

Quote:
Originally Posted by J65nko View Post
With Linux expr works:
Code:
$ if expr 'zzz' \> 'aaa' ; then echo Greater ; fi
Greater
Hmm, what version of expr did you use? I tried three different Linux versions

expr (GNU coreutils) 8.19
expr (GNU coreutils) 8.21
expr (GNU coreutils) 8.4

They all print out the result
Code:
expr aaa \> zzz
0
The Gnu/Linux man page says they print out the result.
Reply With Quote
  #8   (View Single Post)  
Old 3rd January 2016
J65nko J65nko is offline
Administrator
 
Join Date: May 2008
Location: Budel - the Netherlands
Posts: 4,128
Default

Yes, you are right. The GNU coreutils 8.21 expr on a Linux Mint live USB stick also does print out the result:
Code:
mint@mint ~ $ if expr 'zzz' \> 'aaa' ; then echo Greater ; fi
1
Greater
Probably forgot to escape the '>'
Code:
mint@mint ~ $ if expr 'zzz' > 'aaa' ; then echo Greater ; fi
Greater
mint@mint ~ $ ls -l aaa
-rw-r--r-- 1 mint mint 4 Jan  3 21:33 aaa
__________________
You don't need to be a genius to debug a pf.conf firewall ruleset, you just need the guts to run tcpdump
Reply With Quote
  #9   (View Single Post)  
Old 4th January 2016
IdOp's Avatar
IdOp IdOp is offline
Too dumb for a smartphone
 
Join Date: May 2008
Location: twisting on the daemon's fork(2)
Posts: 1,027
Default

Thanks for clarifying. These things happen very easily when experimenting with different variants of programs, OS, example categories, shell syntaxes and so on.
Reply With Quote
Reply

Tags
/bin/test, /bin/[, shell string compare, string compare

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
which shell is better? ibara OpenBSD General 7 14th March 2014 03:00 PM
OpenBSD: Comparing Errata and -Stable jggimi Guides 4 6th June 2012 06:28 AM
ask for a shell script Simon Programming 5 27th April 2010 01:07 AM
Shell Scripting with BSD chavez243 Programming 9 3rd December 2008 03:03 AM
Color shell? giga FreeBSD General 3 14th August 2008 12:07 AM


All times are GMT. The time now is 09:28 PM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Content copyright © 2007-2010, the authors
Daemon image copyright ©1988, Marshall Kirk McKusick