Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am comparing two strings using the levenshtein distance algorithm. I got the PHP implementation of the algorithm from here. I am calling this php implementation from my shell script as below.

levenshtein_return=$(php levensh.php "String1" "String2")

The levenshtein_return variable contains the value as 1 now as there is a single character difference.

Now, before inserting the value as such in database tables, I need to perform some arithmetic operations using this variable. I am trying to implement as,

table_value=$( expr( 1/ ( 1 + $levenshtein_return ) ) )

However, if I use the above syntax I am getting an error as,

line 52: syntax error near unexpected token `1'

How can I change the expr statement so that I can get the actual value for the table_value variable?

share|improve this question

3 Answers 3

up vote 4 down vote accepted

You shouldn't use expr in this case, try this:

table_value=$(( 1 / (1+$levenshtein_return) ))
share|improve this answer
    
Thanks, it worked. –  Ramesh Feb 18 at 1:42

There are a few problems there.

In:

table_value=$( expr( 1/ ( 1 + $levenshtein_return ) ) )

The ( and ) characters are special to the shell so has to be escaped. And it's the expr command you want to run, not the expr( command. Also you must pass operators and operands as separate arguments to expr.

table_value=$(expr '(' 1 / "(" 1 + "$levenshtein_return" \) ')' )

(above showing the different ways you can quote the ( and ) characters).

Now as @Gnouc has shown, expr is no longer necessary for arithmetic evaluation as all modern POSIX shells have a $((...)) built-in operator for that.

Now, except with zsh and ksh93, neither expr nor $((...)) do floating point arithmetic. So in both:

table_value=$(expr 1 / "(" 1 + "$levenshtein_return" ")" )

and

table_value=$((1 / (1 + $levenshtein_return)))

The value will be integer, so typically either 0 or 1.

If you did meant to have 1 if the strings are the same and 0 if they are different (but then, you don't need to calculate a distance if all you want to do is check that two strings are the same), then you'd have written:

table_value=$((!$levenshtein_return))

In ksh93 or zsh, if you wanted a floating point value, you'd write:

table_value=$((1. / (1 + $levenshtein_return)))

In other shells, and POSIXly, if you need floating point arithmetic, you typically call a command that can do it like awk, bc or... php.

Here, as you're already invoking php, you might as well make it do the final calculation as well. If using awk, note that awk can also do the Levenshtein distance calculation easily:

table_value=$(awk '
    function min(x, y) {
      return x < y ? x : y
    }
    function lev(s,t) {
      m = length(s)
      n = length(t)

      for(i=0;i<=m;i++) d[i,0] = i
      for(j=0;j<=n;j++) d[0,j] = j

      for(i=1;i<=m;i++) {
        for(j=1;j<=n;j++) {
          c = substr(s,i,1) != substr(t,j,1)
          d[i,j] = min(d[i-1,j]+1,min(d[i,j-1]+1,d[i-1,j-1]+c))
        }
      }

      return d[m,n]
    }

    BEGIN {print 1 / (1 +lev(ARGV[1], ARGV[2])); exit}' String1 String2
)
share|improve this answer
    
I was trying to do in shell script but did not know floating point calculation was not available in it. Your awk suggestion is working. Instead of calling a php script from my shell script, I can include the awk code inside the shell script itself. Thanks for the answer. –  Ramesh Feb 18 at 15:12
    
@Ramesh, note that you can embed php code as well with php -r: php -r 'function lev...; echo lev(argv[1],argv[2])' String1 String2 –  Stéphane Chazelas Feb 18 at 15:16
    
oh I was not aware of that. I used to invoke the php script located in the same location as my shell script using the php filename command. –  Ramesh Feb 18 at 15:17

While it's not documented and not guaranteed by POSIX, it seems that because POSIX requires shells to handle C constants and many of the same operators C does, they seem to source all of the rest of the simple C integer math operators as well, including ternary tests and assignments:

% a=abc
% b=abcd
% t=1 ; f=0
% echo $((r=${#a}>${#b}?t:f)) ; echo $r
> 0 
> 0
% echo $((r=${#a}<${#b}?t:f)) ; echo $r
> 1
> 1

I've just tested the above basic example in zsh, bash, bash's sh, and dash. All behaved correctly and identically.

share|improve this answer
    
They also all seem to handle bitwise math, like | & ^ << >> but that stuff baffles me so it's in a comment. –  mikeserv Mar 12 at 12:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.