The to_roman ()
is a function definition and not part of the program itself. The actual program starts below that.
before to_roman ()
, the program is simply verifying your input. Did you include a parameter? If not, the first if
statement will catch that.
Is the number greater than 200? If it is greater than 200, the second if
will take care of that.
The heart of the program is:
to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?
The program is running the to_roman
function with the three parameters. The first is the number you want to convert (or what's left of that number. The second is the factor of that number, and the third is the character to print.
The program, is using a loop. For example, if I pass in the parameters 175
, 100
, and C
into the to_roman
function, it subtracts 150 - 100
, sees the results are still greater than 0, and prints out the letter C
and tries again. In this case, it tries it once more, but gets the number -25
. Since it's less than zero, the subroutine exits with 75
. The num=$?
sets number
with the leftover (amount 75
in this case).
This is done for to_roman 75 90 LXXXX
(which doesn't print out anything because 90 - 75
is less than zero), to_roman 75 50 L
(which prints out a single L
because you can subtract a single 50
from 75). The result of that last one is 25
.
Here's something you can do to help you understand a shell script. First:
$ export PS4="$LINENO: "
The PS4
prompt is for debugging. The default PS4
prompt is +
which isn't too useful. This changes the PS4
prompt to the line number of the shell script that is being debugged.
Now, put set -xv
and set +xv
around the area of the shell script your trying to debug. In this case, you probably want to put it at the beginning and ending of the script. Here's my debugging output with the number 175. See if you can follow what's going on:
$ ./roman.sh 175
LIMIT=200
3: LIMIT=200
E_ARG_ERR=65
4: E_ARG_ERR=65
E_OUT_OF_RANGE=66
5: E_OUT_OF_RANGE=66
if [ -z "$1" ]
then
echo "Usage: `basename $0` number-to-convert"
exit $E_ARG_ERR
fi
7: '[' -z 175 ']'
num=$1
13: num=175
if [ "$num" -gt $LIMIT ]
then
echo "Out of range!"
exit $E_OUT_OF_RANGE
fi
14: '[' 175 -gt 200 ']'
to_roman ()
{
number=$1
factor=$2
rchar=$3
let "remainder = number - factor"
while [ "$remainder" -ge 0 ]
do
echo -n $rchar
let "number -= factor"
let "remainder = number - factor"
done
return $number
}
to_roman $num 100 C
35: to_roman 175 100 C
22: number=175
23: factor=100
24: rchar=C
25: let 'remainder = number - factor'
26: '[' 75 -ge 0 ']'
28: echo -n C
C29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -25 -ge 0 ']'
32: return 75
num=$?
36: num=75
to_roman $num 90 LXXXX
37: to_roman 75 90 LXXXX
22: number=75
23: factor=90
24: rchar=LXXXX
25: let 'remainder = number - factor'
26: '[' -15 -ge 0 ']'
32: return 75
num=$?
38: num=75
to_roman $num 50 L
39: to_roman 75 50 L
22: number=75
23: factor=50
24: rchar=L
25: let 'remainder = number - factor'
26: '[' 25 -ge 0 ']'
28: echo -n L
L29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -25 -ge 0 ']'
32: return 25
num=$?
40: num=25
to_roman $num 40 XL
41: to_roman 25 40 XL
22: number=25
23: factor=40
24: rchar=XL
25: let 'remainder = number - factor'
26: '[' -15 -ge 0 ']'
32: return 25
num=$?
42: num=25
to_roman $num 10 X
43: to_roman 25 10 X
22: number=25
23: factor=10
24: rchar=X
25: let 'remainder = number - factor'
26: '[' 15 -ge 0 ']'
28: echo -n X
X29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' 5 -ge 0 ']'
28: echo -n X
X29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -5 -ge 0 ']'
32: return 5
num=$?
44: num=5
to_roman $num 9 IX
45: to_roman 5 9 IX
22: number=5
23: factor=9
24: rchar=IX
25: let 'remainder = number - factor'
26: '[' -4 -ge 0 ']'
32: return 5
num=$?
46: num=5
to_roman $num 5 V
47: to_roman 5 5 V
22: number=5
23: factor=5
24: rchar=V
25: let 'remainder = number - factor'
26: '[' 0 -ge 0 ']'
28: echo -n V
V29: let 'number -= factor'
30: let 'remainder = number - factor'
26: '[' -5 -ge 0 ']'
32: return 0
num=$?
48: num=0
to_roman $num 4 IV
49: to_roman 0 4 IV
22: number=0
23: factor=4
24: rchar=IV
25: let 'remainder = number - factor'
26: '[' -4 -ge 0 ']'
32: return 0
num=$?
50: num=0
to_roman $num 1 I
51: to_roman 0 1 I
22: number=0
23: factor=1
24: rchar=I
25: let 'remainder = number - factor'
26: '[' -1 -ge 0 ']'
32: return 0
echo
52: echo
set -xv
53: set -xv
exit
54: exit