bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Segmentation fault


From: Matthew Woehlke
Subject: Re: Segmentation fault
Date: Tue, 18 Dec 2007 21:21:00 -0600
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.0

(things I forgot to say the first time...)
Matthew Woehlke wrote:
Chet Ramey wrote:
seba wrote:
GNU bash, version 3.2.25(1)-release (i686-pc-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

#!/bin/sh

This is wrong. You're using features that are not in classic Bourne shell. This script will only run on /bin/sh from certain Linux distributions (maybe all, but I wouldn't bank on that, and certainly it won't run on non-Linux platforms). If you want it to run on "/bin/sh", you must avoid using any features not in classic Bourne. In this case, that means particularly $() and $(()) which are POSIX and Bash extensions, respectively.

fib() {
       n=$1
       [ $n == 0 -o $n == 1 ] && return $n
       fib $(($n-1))
       ret1=$?
       fib $(($n-2))
       ret2=$?
       return $(($ret1 + $ret2))
}

for ((i=0;$i<36;i++))
do
       fib $i
       echo "n=$i=>$?"
done

You managed to write yourself an infinitely-recursive function, and
eventually ran out of stack space.  `==' is a string operator, not a
numeric operator, when used with `['.

Why is [ 0 == 0 ] any more or less true than [ 0 -eq 0 ]?

The problem seems to be that this line is missing from the function:
local n ret1 ret2

Oh, and return values wrap at 255, so using the return code only works up to n=13. Use substitution ($()) and have the function 'echo' the result.

...which results in subshells being created, which is inefficient but obviates the need to use 'local' (and is therefore more portable as well).

Here's a version that should run on "/bin/sh". If you can count on using bash, you can make it quite a bit prettier with $() and $(()) instead of `'s, expr and seq.

#!/bin/sh

fib() {
       n=$1
       [ $n == 0 ] || [ $n == 1 ] && echo $n && return
       ret1=`fib \`expr $n - 1\``
       ret2=`fib \`expr $n - 2\``
       expr $ret1 + $ret2
}

for i in `seq 0 36`
do
       echo "n=$i=>`fib $i`"
done

IOW, like this:

#!/bin/bash

fib() {
       n=$1
       [ $n == 0 ] || [ $n == 1 ] && echo $n && return
       ret1=$(fib $(($n-1)))
       ret2=$(fib $(($n-2)))
       echo $(($ret1 + $ret2))
}

for ((i=0;$i<36;i++))
do
       echo "n=$i=>$(fib $i)"
done

...which only works when /bin/bash exists, of course. I haven't tried the first one, but the second got me to 'n=23=>28657' before I killed it for being slow :-).

--
Matthew
"Who wants to sing?" -- Orcs (Warcraft II)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]