Почему моя функция bash возвращает неправильное значение? - PullRequest
3 голосов
/ 03 августа 2010
fact() 
{
    if [ $1 -eq 1 ]
    then
        return 1
    else
        y=`expr $1 - 1`
        fact $y
        b=$(($1 * $?))
        return $b
    fi
}
echo "enter"
read n
fact $n
echo "$?"

Это программа для поиска факториала числа. Вывод правильный до 5. Выход 6 дает 208, но правильный ответ - 720. Что вызывает эту ошибку?

Ответы [ 5 ]

7 голосов
/ 03 августа 2010

Возвращаемые значения функции могут доходить только до 255:

a()
{
        return 255
}

a
echo $?

b()
{
        return 256
}

b
echo $?

Производит:

$ bash x.sh
255
0

return похоже на exit, а exit может принимать значения только до 255 (http://www.unix.org/whitepapers/shdiffs.html).

Одна альтернатива - перейти к итеративному предложению, как описано в другом ответе. В качестве альтернативы вы можете использовать echo и перехватить рекурсивный вывод следующим образом:

#!/bin/bash

fact() 
{
    if [ $1 -eq 1 ]
    then
        echo 1
    else
        y=$(expr $1 - 1)
        f=$(fact $y)
        b=$(($1 * $f))
        echo $b
    fi
}
echo "enter"
read n
fact $n
2 голосов
/ 03 августа 2010

То, что вы видите, - это возврат значений функции на 256. 720 mod 256 равен 208 (256 + 256 + 208 = 720).

Мой совет, если вы должны использоватьФункция оболочки, должна сделать:

#!/bin/bash
fact()
{
    if [ "$1" -eq "1" ]
    then
        echo 1
        return
    fi
    y=`expr $1 - 1`
    z=$(fact $y)
    echo $(($1 * $z))
}
echo "enter"
read n
echo "$(fact $n)"

Используется стандартный вывод для возврата значений, а не код возврата.

Или, что еще лучше, используйте вправо инструменты для работы:

pax> echo 'define f(x) {if (x>1){return x*f(x-1)};return 1}
           f(6)' | bc
720
pax> echo 'define f(x) {if (x>1){return x*f(x-1)};return 1}
           f(500)' | BC_LINE_LENGTH=99999 bc
12201368259911100687012387854230469262535743428031928421924135883858
45373153881997605496447502203281863013616477148203584163378722078177
20048078520515932928547790757193933060377296085908627042917454788242
49127263443056701732707694610628023104526442188787894657547771498634
94367781037644274033827365397471386477878495438489595537537990423241
06127132698432774571554630997720278101456108118837370953101635632443
29870295638966289116589747695720879269288712817800702651745077684107
19624390394322536422605234945850129918571501248706961568141625359056
69342381300885624924689156412677565448188650659384795177536089400574
52389403357984763639449053130623237490664450488246650759467358620746
37925184200459369692981022263971952597190945217823331756934581508552
33282076282002340262690789834245171200620771464097945611612762914595
12372299133401695523638509428855920187274337951730145863575708283557
80158735432768888680120399882384702151467605445407663535984174430480
12893831389688163948746965881750450692636533817505547812864000000000
00000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000

Мне бы очень хотелось, чтобы bash -только решение вычислило факториал 500: -)

2 голосов
/ 03 августа 2010

Bourne Shell не может хранить много в $?(код выхода).ограничение 255. Вот альтернативный путь

n=0
on=0
fact=1 

echo -n "Enter number to find factorial : "
read n

on=$n

while [ $n -ge  1 ]
do
  fact=`expr $fact \* $n`
  n=`expr $n - 1`
done

echo "Factorial for $on is $fact"
1 голос
/ 03 августа 2010

Возвращаемые значения скриптов Bash и функций Bash предназначены для возврата кодов и, следовательно, ограничены значениями, которые они могут возвращать. Вы не должны зависеть от значений, превышающих 127 (обычно значения, превышающие 127 - до 255 - используются для указания полученных сигналов).

Линии

fact $y
b=$(($1 * $?))

ожидается использование кода возврата $? из fact, и этот код не может быть больше 255.

Способ возврата значений в Bash - это печать их, анализ или оценка этого вывода.

1 голос
/ 03 августа 2010

Интересно, что программа работает, как и ожидалось, используя dash, она не работает только при использовании bash. Похоже, это башизм.

Просто добавьте строку

#!/bin/dash

вверху программы и все работает!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...